diff options
22 files changed, 275 insertions, 203 deletions
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 9a067e761d7..b2ecd28e884 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -213,9 +213,7 @@ bool BKE_paint_always_hide_test(struct Object *ob); /** * Returns non-zero if any of the face's vertices are hidden, zero otherwise. */ -bool paint_is_face_hidden(const struct MLoopTri *lt, - const bool *hide_vert, - const struct MLoop *mloop); +bool paint_is_face_hidden(const struct MLoopTri *lt, const bool *hide_poly); /** * Returns non-zero if any of the corners of the grid * face whose inner corner is at (x, y) are hidden, zero otherwise. @@ -689,7 +687,7 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph, bool need_pmap, bool need_mask, bool is_paint_tool); -void BKE_sculpt_update_object_before_eval(const struct Scene *scene, struct Object *ob_eval); +void BKE_sculpt_update_object_before_eval(struct Object *ob_eval); void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval); /** @@ -698,6 +696,7 @@ void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Obj */ struct MultiresModifierData *BKE_sculpt_multires_active(const struct Scene *scene, struct Object *ob); +int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh); int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene); @@ -719,18 +718,17 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg); /** - * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the - * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the - * mesh to the Face Sets. */ -void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh); + * If a face set layer exists, initialize its visiblity (sign) from the mesh's hidden values. + */ +void BKE_sculpt_face_sets_update_from_base_mesh_visibility(struct Mesh *mesh); /** - * Ensures we do have expected mesh data in original mesh for the sculpt mode. + * Makes sculpt data consistent with other data on the mesh. * * \note IDs are expected to be original ones here, and calling code should ensure it updates its * depsgraph properly after calling this function if it needs up-to-date evaluated data. */ -void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object); +void BKE_sculpt_ensure_orig_mesh_data(struct Object *object); /** * Test if PBVH can be used directly for drawing, which is faster than diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 716ee7d2a21..403f3a31ba0 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -674,6 +674,8 @@ const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]; const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh); bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh); +const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh); + PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node); void BKE_pbvh_node_color_buffer_free(PBVH *pbvh); bool BKE_pbvh_get_color_layer(const struct Mesh *me, diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 986e10b3a16..d7db0ad765c 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -1720,7 +1720,7 @@ void makeDerivedMesh(struct Depsgraph *depsgraph, BKE_object_free_derived_caches(ob); if (DEG_is_active(depsgraph)) { - BKE_sculpt_update_object_before_eval(scene, ob); + BKE_sculpt_update_object_before_eval(ob); } /* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index f5f460c6ed4..fd4696f97fb 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1247,13 +1247,12 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p) } } -bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_vert, const MLoop *mloop) +bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_poly) { - if (!hide_vert) { + if (!hide_poly) { return false; } - return ((hide_vert[mloop[lt->tri[0]].v]) || (hide_vert[mloop[lt->tri[1]].v]) || - (hide_vert[mloop[lt->tri[2]].v])); + return hide_poly[lt->poly]; } bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y) @@ -1632,15 +1631,8 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) return false; } -/** - * \param need_mask: So that the evaluated mesh that is returned has mask data. - */ -static void sculpt_update_object(Depsgraph *depsgraph, - Object *ob, - Object *ob_eval, - bool need_pmap, - bool need_mask, - bool is_paint_tool) +static void sculpt_update_object( + Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool) { Scene *scene = DEG_get_input_scene(depsgraph); Sculpt *sd = scene->toolsettings->sculpt; @@ -1662,15 +1654,6 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->scene = scene; - if (need_mask) { - if (mmd == nullptr) { - BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK)); - } - else { - BLI_assert(CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)); - } - } - ss->shapekey_active = (mmd == nullptr) ? BKE_keyblock_from_object(ob) : nullptr; /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, @@ -1726,7 +1709,6 @@ static void sculpt_update_object(Depsgraph *depsgraph, /* Sculpt Face Sets. */ if (use_face_sets) { - BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)); ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS)); } else { @@ -1859,24 +1841,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, } } -static void sculpt_face_sets_ensure(Mesh *mesh) -{ - if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { - return; - } - - int *new_face_sets = static_cast<int *>(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); - - /* Initialize the new Face Set data-layer with a default valid visible ID and set the default - * color to render it white. */ - for (int i = 0; i < mesh->totpoly; i++) { - new_face_sets[i] = 1; - } - mesh->face_sets_color_default = 1; -} - -void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval) +void BKE_sculpt_update_object_before_eval(Object *ob_eval) { /* Update before mesh evaluation in the dependency graph. */ SculptSession *ss = ob_eval->sculpt; @@ -1906,16 +1871,6 @@ void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval) MEM_freeN(nodes); } } - - if (ss) { - Object *ob_orig = DEG_get_original_object(ob_eval); - Mesh *mesh = BKE_object_get_original_mesh(ob_orig); - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob_orig); - - /* Ensure attribute layout is still correct. */ - sculpt_face_sets_ensure(mesh); - BKE_sculpt_mask_layers_ensure(ob_orig, mmd); - } } void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) @@ -1924,7 +1879,7 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) * other data when modifiers change the mesh. */ Object *ob_orig = DEG_get_original_object(ob_eval); - sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false, false); + sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false); } void BKE_sculpt_color_layer_create_if_needed(Object *object) @@ -1962,13 +1917,53 @@ void BKE_sculpt_color_layer_create_if_needed(Object *object) } void BKE_sculpt_update_object_for_edit( - Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool is_paint_tool) + Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool /*need_mask*/, bool is_paint_tool) { BLI_assert(ob_orig == DEG_get_original_object(ob_orig)); Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig); - sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, need_mask, is_paint_tool); + sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, is_paint_tool); +} + +int *BKE_sculpt_face_sets_ensure(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { + return static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); + } + + const AttributeAccessor attributes = mesh->attributes_for_write(); + const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( + ".hide_poly", ATTR_DOMAIN_FACE, false); + + MutableSpan<int> face_sets = { + static_cast<int *>(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)), + mesh->totpoly}; + + /* Initialize the new face sets with a default valid visible ID and set the default + * color to render it white. */ + if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + face_sets.fill(1); + } + else { + const int face_sets_default_visible_id = 1; + const int face_sets_default_hidden_id = -(face_sets_default_visible_id + 1); + + const VArraySpan<bool> hide_poly_span{hide_poly}; + for (const int i : face_sets.index_range()) { + /* Assign a new hidden ID to hidden faces. This way we get at initial split in two Face Sets + * between hidden and visible faces based on the previous mesh visibly from other mode that + * can be useful in some cases. */ + face_sets[i] = hide_poly_span[i] ? face_sets_default_hidden_id : + face_sets_default_visible_id; + } + } + + mesh->face_sets_color_default = 1; + return face_sets.data(); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) @@ -2092,67 +2087,48 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc return deformed; } -void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) +void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh) { - const int face_sets_default_visible_id = 1; - const int face_sets_default_hidden_id = -(face_sets_default_visible_id + 1); - - bool initialize_new_face_sets = false; - - if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { - /* Make everything visible. */ - int *current_face_sets = static_cast<int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - for (int i = 0; i < mesh->totpoly; i++) { - current_face_sets[i] = abs(current_face_sets[i]); - } - } - else { - initialize_new_face_sets = true; - int *new_face_sets = static_cast<int *>(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); - - /* Initialize the new Face Set data-layer with a default valid visible ID and set the default - * color to render it white. */ - for (int i = 0; i < mesh->totpoly; i++) { - new_face_sets[i] = face_sets_default_visible_id; - } - mesh->face_sets_color_default = face_sets_default_visible_id; + using namespace blender; + using namespace blender::bke; + if (!CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { + return; } - int *face_sets = static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - const bool *hide_poly = (const bool *)CustomData_get_layer_named( - &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); + const AttributeAccessor attributes = mesh->attributes(); + const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( + ".hide_poly", ATTR_DOMAIN_FACE, false); + if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + return; + } - for (int i = 0; i < mesh->totpoly; i++) { - if (!(hide_poly && hide_poly[i])) { - continue; - } + MutableSpan<int> face_sets{ + static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)), mesh->totpoly}; - if (initialize_new_face_sets) { - /* When initializing a new Face Set data-layer, assign a new hidden Face Set ID to hidden - * vertices. This way, we get at initial split in two Face Sets between hidden and - * visible vertices based on the previous mesh visibly from other mode that can be - * useful in some cases. */ - face_sets[i] = face_sets_default_hidden_id; - } - else { - /* Otherwise, set the already existing Face Set ID to hidden. */ - face_sets[i] = -abs(face_sets[i]); - } + for (const int i : hide_poly.index_range()) { + face_sets[i] = hide_poly[i] ? -std::abs(face_sets[i]) : std::abs(face_sets[i]); } } -void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +static void set_hide_poly_from_face_sets(Mesh &mesh) { + using namespace blender; using namespace blender::bke; - const int *face_sets = static_cast<const int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - if (!face_sets) { + if (!CustomData_has_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)) { + return; + } + + const Span<int> face_sets{ + static_cast<const int *>(CustomData_get_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)), + mesh.totpoly}; + + MutableAttributeAccessor attributes = mesh.attributes_for_write(); + if (std::all_of( + face_sets.begin(), face_sets.end(), [&](const int value) { return value > 0; })) { + attributes.remove(".hide_poly"); return; } - MutableAttributeAccessor attributes = mesh->attributes_for_write(); SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( ".hide_poly", ATTR_DOMAIN_FACE); if (!hide_poly) { @@ -2162,7 +2138,11 @@ void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) hide_poly.span[i] = face_sets[i] < 0; } hide_poly.finish(); +} +void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +{ + set_hide_poly_from_face_sets(*mesh); BKE_mesh_flush_hidden_from_polys(mesh); } @@ -2200,41 +2180,29 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv void BKE_sculpt_sync_face_set_visibility(Mesh *mesh, SubdivCCG *subdiv_ccg) { - BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); + BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh); BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh); BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg); } -void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object) +void BKE_sculpt_ensure_orig_mesh_data(Object *object) { Mesh *mesh = BKE_mesh_from_object(object); - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, object); - BLI_assert(object->mode == OB_MODE_SCULPT); /* Copy the current mesh visibility to the Face Sets. */ - BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); - if (object->sculpt != nullptr) { - /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */ - object->sculpt->face_sets = static_cast<int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - - /* NOTE: In theory we could add that on the fly when required by sculpt code. - * But this then requires proper update of depsgraph etc. For now we play safe, optimization is - * always possible later if it's worth it. */ - BKE_sculpt_mask_layers_ensure(object, mmd); - } + BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh); /* Tessfaces aren't used and will become invalid. */ BKE_mesh_tessface_clear(mesh); /* We always need to flush updates from depsgraph here, since at the very least - * `BKE_sculpt_face_sets_ensure_from_base_mesh_visibility()` will have updated some data layer of + * `BKE_sculpt_face_sets_update_from_base_mesh_visibility()` will have updated some data layer of * the mesh. * * All known potential sources of updates: * - Addition of, or changes to, the `CD_SCULPT_FACE_SETS` data layer - * (`BKE_sculpt_face_sets_ensure_from_base_mesh_visibility`). + * (`BKE_sculpt_face_sets_update_from_base_mesh_visibility`). * - Addition of a `CD_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`). * - Object has any active modifier (modifier stack can be different in Sculpt mode). * - Multires: diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 6d761f56f13..2de5c718918 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -285,7 +285,7 @@ static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node) } if (has_visible == false) { - if (!paint_is_face_hidden(lt, pbvh->hide_vert, pbvh->mloop)) { + if (!paint_is_face_hidden(lt, pbvh->hide_poly)) { has_visible = true; } } @@ -552,6 +552,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, pbvh->mesh = mesh; pbvh->header.type = PBVH_FACES; pbvh->mpoly = mpoly; + pbvh->hide_poly = (bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly"); pbvh->material_indices = (const int *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_INT32, "material_index"); pbvh->mloop = mloop; @@ -1313,11 +1314,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } case PBVH_FACES: node->draw_buffers = GPU_pbvh_mesh_buffers_build( - pbvh->mesh, - pbvh->looptri, - CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), - node->prim_indices, - node->totprim); + pbvh->mesh, pbvh->looptri, node->prim_indices, node->totprim); break; case PBVH_BMESH: node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags & @@ -2293,7 +2290,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, const MLoopTri *lt = &pbvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) { continue; } @@ -2602,7 +2599,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh, const MLoopTri *lt = &pbvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) { continue; } @@ -3219,6 +3216,12 @@ const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh) return pbvh->hide_vert; } +const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh) +{ + BLI_assert(pbvh->header.type == PBVH_FACES); + return pbvh->hide_poly; +} + bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh) { BLI_assert(pbvh->header.type == PBVH_FACES); diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index b848327b7a9..8ab56839f9c 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -156,6 +156,7 @@ struct PBVH { bool *hide_vert; struct MVert *verts; const struct MPoly *mpoly; + bool *hide_poly; /** Material indices. Only valid for polygon meshes. */ const int *material_indices; const struct MLoop *mloop; diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index a6b51048209..aa8dc4debd9 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -186,7 +186,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) } if (ob->mode == OB_MODE_SCULPT) { - BKE_sculpt_ensure_orig_mesh_data(CTX_data_scene(C), ob); + BKE_sculpt_ensure_orig_mesh_data(ob); ED_sculpt_undo_geometry_end(ob); } @@ -912,7 +912,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update } if (ob->mode == OB_MODE_SCULPT) { - BKE_sculpt_ensure_orig_mesh_data(qj->scene, ob); + BKE_sculpt_ensure_orig_mesh_data(ob); ED_sculpt_undo_geometry_end(ob); } diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0ea45f83336..437ff7506ba 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -134,6 +134,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata, static int mask_flood_fill_exec(bContext *C, wmOperator *op) { + const Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); PaintMaskFloodMode mode; @@ -146,6 +147,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) mode = RNA_enum_get(op->ptr, "mode"); value = RNA_float_get(op->ptr, "value"); + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); @@ -774,6 +778,8 @@ static void sculpt_gesture_init_face_set_properties(SculptGestureContext *sgcont struct Mesh *mesh = BKE_mesh_from_object(sgcontext->vc.obact); sgcontext->operation = MEM_callocN(sizeof(SculptGestureFaceSetOperation), "Face Set Operation"); + sgcontext->ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + SculptGestureFaceSetOperation *face_set_operation = (SculptGestureFaceSetOperation *) sgcontext->operation; @@ -817,7 +823,7 @@ static void mask_gesture_apply_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { - float prevmask = *vd.mask; + float prevmask = vd.mask ? *vd.mask : 0.0f; if (!any_masked) { any_masked = true; @@ -863,6 +869,10 @@ static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext, SculptGestureMaskOperation *mask_operation = (SculptGestureMaskOperation *)sgcontext->operation; + Object *object = sgcontext->vc.obact; + MultiresModifierData *mmd = BKE_sculpt_multires_active(sgcontext->vc.scene, object); + BKE_sculpt_mask_layers_ensure(sgcontext->vc.obact, mmd); + mask_operation->op.sculpt_gesture_begin = sculpt_gesture_mask_begin; mask_operation->op.sculpt_gesture_apply_for_symmetry_pass = sculpt_gesture_mask_apply_for_symmetry_pass; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 51ff064c58d..119bd254abf 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -253,11 +253,11 @@ float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex) float *mask; switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->vmask[vertex.i]; + return ss->vmask ? ss->vmask[vertex.i] : 0.0f; case PBVH_BMESH: v = (BMVert *)vertex.i; mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); - return *mask; + return mask ? *mask : 0.0f; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; @@ -329,7 +329,7 @@ int SCULPT_active_face_set_get(SculptSession *ss) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->face_sets[ss->active_face_index]; + return ss->face_sets ? ss->face_sets[ss->active_face_index] : SCULPT_FACE_SET_NONE; case PBVH_GRIDS: { const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, ss->active_grid_index); @@ -383,6 +383,7 @@ bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex) void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible) { + BLI_assert(ss->face_sets != NULL); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: @@ -405,6 +406,7 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl void SCULPT_face_sets_visibility_invert(SculptSession *ss) { + BLI_assert(ss->face_sets != NULL); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: @@ -422,6 +424,9 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: + if (!ss->face_sets) { + return; + } for (int i = 0; i < ss->totfaces; i++) { /* This can run on geometry without a face set assigned, so its ID sign can't be changed to @@ -446,11 +451,15 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible) bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex) { + const bool *hide_poly = BKE_pbvh_get_poly_hide(ss->pbvh); + if (!hide_poly) { + return true; + } switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < ss->pmap[vertex.i].count; j++) { - if (ss->face_sets[vert_map->indices[j]] > 0) { + if (!hide_poly[vert_map->indices[j]]) { return true; } } @@ -466,11 +475,15 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef verte bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex) { + const bool *hide_poly = BKE_pbvh_get_poly_hide(ss->pbvh); + if (!hide_poly) { + return true; + } switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < ss->pmap[vertex.i].count; j++) { - if (ss->face_sets[vert_map->indices[j]] < 0) { + if (hide_poly[vert_map->indices[j]]) { return false; } } @@ -482,7 +495,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRe const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); - return ss->face_sets[face_index] > 0; + return !hide_poly[face_index]; } } return true; @@ -492,6 +505,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_ { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { + BLI_assert(ss->face_sets != NULL); MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] > 0) { @@ -502,6 +516,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_ case PBVH_BMESH: break; case PBVH_GRIDS: { + BLI_assert(ss->face_sets != NULL); const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); @@ -517,6 +532,9 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { + if (!ss->face_sets) { + return SCULPT_FACE_SET_NONE; + } MeshElemMap *vert_map = &ss->pmap[vertex.i]; int face_set = 0; for (int i = 0; i < ss->pmap[vertex.i].count; i++) { @@ -529,6 +547,9 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) case PBVH_BMESH: return 0; case PBVH_GRIDS: { + if (!ss->face_sets) { + return SCULPT_FACE_SET_NONE; + } const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); @@ -542,6 +563,9 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_ { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { + if (!ss->face_sets) { + return face_set == SCULPT_FACE_SET_NONE; + } MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] == face_set) { @@ -553,6 +577,9 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_ case PBVH_BMESH: return true; case PBVH_GRIDS: { + if (!ss->face_sets) { + return face_set == SCULPT_FACE_SET_NONE; + } const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); @@ -599,6 +626,9 @@ static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSe void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) { if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { + if (ss->face_sets == NULL) { + return; + } for (int i = 0; i < ss->totfaces; i++) { const MPoly *poly = &ss->mpoly[i]; bool poly_visible = true; @@ -620,6 +650,9 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index) { + if (!ss->face_sets) { + return true; + } MeshElemMap *vert_map = &ss->pmap[index]; int face_set = -1; for (int i = 0; i < ss->pmap[index].count; i++) { @@ -676,6 +709,9 @@ bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex) case PBVH_BMESH: return true; case PBVH_GRIDS: { + if (!ss->face_sets) { + return true; + } const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int vertex_index = vertex.i - grid_index * key->grid_area; @@ -703,6 +739,9 @@ int SCULPT_face_set_next_available_get(SculptSession *ss) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: { + if (!ss->face_sets) { + return 0; + } int next_face_set = 0; for (int i = 0; i < ss->totfaces; i++) { if (abs(ss->face_sets[i]) > next_face_set) { @@ -792,9 +831,10 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; iter->neighbor_indices = iter->neighbor_indices_fixed; + const bool *hide_poly = BKE_pbvh_get_vert_hide(ss->pbvh); for (int i = 0; i < ss->pmap[vertex.i].count; i++) { - if (ss->face_sets[vert_map->indices[i]] < 0) { + if (hide_poly && hide_poly[vert_map->indices[i]]) { /* Skip connectivity from hidden faces. */ continue; } @@ -3302,6 +3342,15 @@ static void do_brush_action(Sculpt *sd, BKE_pbvh_ensure_node_loops(ss->pbvh); } + if (SCULPT_tool_is_mask(brush->sculpt_tool)) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + } + if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) { + Mesh *mesh = BKE_object_get_original_mesh(ob); + ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + } + /* Build a list of all nodes that are potentially within the brush's area of influence */ if (SCULPT_tool_needs_all_pbvh_nodes(brush)) { diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index ad8a1cde9dc..46674c5d239 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -215,13 +215,7 @@ static void SCULPT_dynamic_topology_disable_ex( BKE_sculptsession_bm_to_me(ob, true); /* Reset Face Sets as they are no longer valid. */ - if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, NULL, me->totpoly); - } - ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); - for (int i = 0; i < me->totpoly; i++) { - ss->face_sets[i] = 1; - } + CustomData_free_layers(&me->pdata, CD_SCULPT_FACE_SETS, me->totpoly); me->face_sets_color_default = 1; /* Sync the visibility to vertices manually as the pmap is still not initialized. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 4aafeacfbff..414a855ab2f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -17,6 +17,7 @@ #include "DNA_brush_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "BKE_brush.h" @@ -1390,9 +1391,15 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c /* Face Sets are always stored as they are needed for snapping. */ expand_cache->initial_face_sets = MEM_malloc_arrayN(totface, sizeof(int), "initial face set"); expand_cache->original_face_sets = MEM_malloc_arrayN(totface, sizeof(int), "original face set"); - for (int i = 0; i < totface; i++) { - expand_cache->initial_face_sets[i] = ss->face_sets[i]; - expand_cache->original_face_sets[i] = ss->face_sets[i]; + if (ss->face_sets) { + for (int i = 0; i < totface; i++) { + expand_cache->initial_face_sets[i] = ss->face_sets[i]; + expand_cache->original_face_sets[i] = ss->face_sets[i]; + } + } + else { + memset(expand_cache->initial_face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * totface); + memset(expand_cache->original_face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * totface); } if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { @@ -2118,6 +2125,16 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even return OPERATOR_CANCELLED; } + if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS) { + Mesh *mesh = ob->data; + ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + } + + if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + } + /* Face Set operations are not supported in dyntopo. */ if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS && BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 64bc6188bbc..e66a7f8b9de 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -303,6 +303,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + Mesh *mesh = ob->data; + ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false); const int tot_vert = SCULPT_vertex_count_get(ss); @@ -349,7 +352,6 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (all_visible) { - Mesh *mesh = ob->data; mesh->face_sets_color_default = next_face_set; BKE_pbvh_face_sets_color_set( ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); @@ -373,7 +375,6 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_SELECTION) { - Mesh *mesh = ob->data; BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); bm = BM_mesh_create(&allocsize, @@ -850,6 +851,10 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (!pbvh_has_face_sets(ss->pbvh)) { + return OPERATOR_CANCELLED; + } + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); const int tot_vert = SCULPT_vertex_count_get(ss); @@ -1000,6 +1005,10 @@ static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSE return OPERATOR_CANCELLED; } + if (!pbvh_has_face_sets(ss->pbvh)) { + return OPERATOR_CANCELLED; + } + PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; int totnode; @@ -1154,7 +1163,9 @@ static void sculpt_face_set_shrink(Object *ob, static bool check_single_face_set(SculptSession *ss, int *face_sets, const bool check_visible_only) { - + if (face_sets == NULL) { + return true; + } int first_face_set = SCULPT_FACE_SET_NONE; if (check_visible_only) { for (int f = 0; f < ss->totfaces; f++) { diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index cba1d3dcdc1..bb27e4f1e9e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -14,6 +14,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -174,11 +175,15 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + const Scene *scene = CTX_data_scene(C); PBVHNode **nodes; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; int totnode; int filter_type = RNA_enum_get(op->ptr, "filter_type"); + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); SculptSession *ss = ob->sculpt; diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c index a5885092ee3..c0856ab21d2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_geodesic.c +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c @@ -170,6 +170,8 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, } } + const bool *hide_poly = BKE_pbvh_get_poly_hide(ss->pbvh); + /* Add edges adjacent to an initial vertex to the queue. */ for (int i = 0; i < totedge; i++) { const int v1 = edges[i].v1; @@ -199,7 +201,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, if (ss->epmap[e].count != 0) { for (int poly_map_index = 0; poly_map_index < ss->epmap[e].count; poly_map_index++) { const int poly = ss->epmap[e].indices[poly_map_index]; - if (ss->face_sets[poly] <= 0) { + if (hide_poly && hide_poly[poly]) { continue; } const MPoly *mpoly = &polys[poly]; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 4bc06d68a02..7a72e5cc84b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1837,6 +1837,16 @@ BLI_INLINE bool SCULPT_tool_is_paint(int tool) return ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR); } +BLI_INLINE bool SCULPT_tool_is_mask(int tool) +{ + return ELEM(tool, SCULPT_TOOL_MASK); +} + +BLI_INLINE bool SCULPT_tool_is_face_sets(int tool) +{ + return ELEM(tool, SCULPT_TOOL_DRAW_FACE_SETS); +} + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 9556d24f12c..ec246cd3788 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -391,7 +391,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent if (create_face_set) { ss->filter_cache->prev_face_set = MEM_callocN(sizeof(float) * ss->totfaces, "prev face mask"); for (int i = 0; i < ss->totfaces; i++) { - ss->filter_cache->prev_face_set[i] = ss->face_sets[i]; + ss->filter_cache->prev_face_set[i] = ss->face_sets ? ss->face_sets[i] : 0; } ss->filter_cache->new_face_set = SCULPT_face_set_next_available_get(ss); } diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 10a2ece73de..055e02a5703 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -300,28 +300,30 @@ static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); ob->sculpt->mode_type = OB_MODE_SCULPT; - BKE_sculpt_ensure_orig_mesh_data(scene, ob); + BKE_sculpt_ensure_orig_mesh_data(ob); BKE_scene_graph_evaluated_ensure(depsgraph, bmain); /* This function expects a fully evaluated depsgraph. */ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - /* Here we can detect geometry that was just added to Sculpt Mode as it has the - * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ - /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not - * initialized, which is used is some operators that modify the mesh topology to perform certain - * actions in the new polys. After these operations are finished, all polys should have a valid - * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility - * correctly. */ - /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new - * objects, like moving the transform pivot position to the new area or masking existing - * geometry. */ SculptSession *ss = ob->sculpt; - const int new_face_set = SCULPT_face_set_next_available_get(ss); - for (int i = 0; i < ss->totfaces; i++) { - if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { - ss->face_sets[i] = new_face_set; + if (ss->face_sets) { + /* Here we can detect geometry that was just added to Sculpt Mode as it has the + * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ + /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not + * initialized, which is used is some operators that modify the mesh topology to perform + * certain actions in the new polys. After these operations are finished, all polys should have + * a valid face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their + * visibility correctly. */ + /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new + * objects, like moving the transform pivot position to the new area or masking existing + * geometry. */ + const int new_face_set = SCULPT_face_set_next_available_get(ss); + for (int i = 0; i < ss->totfaces; i++) { + if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { + ss->face_sets[i] = new_face_set; + } } } } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index a31be07d8af..22928a8c934 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -476,7 +476,8 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = BKE_view_layer_active_object_get(view_layer); Mesh *me = BKE_object_get_original_mesh(ob); - int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); + int *face_sets = CustomData_add_layer( + &me->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, NULL, me->totpoly); for (int i = 0; i < me->totpoly; i++) { face_sets[i] = unode->face_sets[i]; } @@ -1354,8 +1355,13 @@ static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType typ unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets"); const int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); - for (int i = 0; i < me->totpoly; i++) { - unode->face_sets[i] = face_sets[i]; + if (face_sets) { + for (int i = 0; i < me->totpoly; i++) { + unode->face_sets[i] = face_sets[i]; + } + } + else { + memset(unode->face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * me->totpoly); } BLI_addtail(&usculpt->nodes, unode); @@ -1513,7 +1519,9 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType sculpt_undo_store_hidden(ob, unode); break; case SCULPT_UNDO_MASK: - sculpt_undo_store_mask(ob, unode); + if (pbvh_has_mask(ss->pbvh)) { + sculpt_undo_store_mask(ob, unode); + } break; case SCULPT_UNDO_COLOR: sculpt_undo_store_color(ob, unode); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index d1d91cb7508..5cdc5f19540 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -49,7 +49,6 @@ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct Mesh *mesh, const struct MLoopTri *looptri, - const int *sculpt_face_sets, const int *face_indices, int face_indices_len); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 8e3058b884d..78f595cbff2 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -210,13 +210,9 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) /** \name Mesh PBVH * \{ */ -static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, - const bool *hide_vert, - const MLoop *mloop, - const int *sculpt_face_sets) +static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, const bool *hide_poly) { - return (!paint_is_face_hidden(lt, hide_vert, mloop) && sculpt_face_sets && - sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE); + return !paint_is_face_hidden(lt, hide_poly); } void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, @@ -233,8 +229,8 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPUAttrRef vcol_refs[MAX_GPU_ATTR]; GPUAttrRef cd_uvs[MAX_GPU_ATTR]; - const bool *hide_vert = (const bool *)CustomData_get_layer_named( - &mesh->vdata, CD_PROP_BOOL, ".hide_vert"); + const bool *hide_poly = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); const int *material_indices = (const int *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_INT32, "material_index"); @@ -315,7 +311,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } @@ -355,7 +351,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, buffers->mloop[lt->tri[2]].v, }; - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } @@ -395,7 +391,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, buffers->mloop[lt->tri[2]].v, }; - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } @@ -459,7 +455,6 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, const MLoopTri *looptri, - const int *sculpt_face_sets, const int *face_indices, const int face_indices_len) { @@ -472,8 +467,8 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - const bool *hide_vert = (bool *)CustomData_get_layer_named( - &mesh->vdata, CD_PROP_BOOL, ".hide_vert"); + const bool *hide_poly = (bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); /* smooth or flat for all */ buffers->smooth = polys[looptri[face_indices[0]].poly].flag & ME_SMOOTH; @@ -483,7 +478,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, /* Count the number of visible triangles */ for (i = 0, tottri = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; - if (gpu_pbvh_is_looptri_visible(lt, hide_vert, loops, sculpt_face_sets)) { + if (gpu_pbvh_is_looptri_visible(lt, hide_poly)) { int r_edges[3]; BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); for (int j = 0; j < 3; j++) { @@ -516,7 +511,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, const MLoopTri *lt = &looptri[face_indices[i]]; /* Skip hidden faces */ - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, loops, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index e15054bd045..db14d7fbeb9 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -136,9 +136,7 @@ eAttrDomain BKE_id_attribute_domain(const struct ID *UNUSED(id), /* -------------------------------------------------------------------- */ /** \name Stubs of BKE_paint.h * \{ */ -bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt), - const bool *UNUSED(hide_vert), - const struct MLoop *UNUSED(mloop)) +bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt), const bool *UNUSED(hide_poly)) { BLI_assert_unreachable(); return false; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 6cbc24db2d8..cfc3a832166 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -500,7 +500,7 @@ void rna_Object_data_update(Main *bmain, Scene *scene, PointerRNA *ptr) Object *object = (Object *)ptr->data; if (object->mode == OB_MODE_SCULPT) { - BKE_sculpt_ensure_orig_mesh_data(scene, object); + BKE_sculpt_ensure_orig_mesh_data(object); } rna_Object_internal_update_data_dependency(bmain, scene, ptr); |