Sculpt: Separate hide status from face sets, use generic attribute

Whether faces are hidden and face sets are orthogonal concepts, but
currently sculpt mode stores them together in the face set array.
This means that if anything is hidden, there must be face sets,
and if there are face sets, we have to keep track of what is hidden.
In other words, it adds a bunch of redundant work and state tracking.

On the user level it's nice that face sets and hiding are consistent,
but we don't need to store them together to accomplish that.

This commit uses the `".hide_poly"` attribute from rB2480b55f216c to
read and change hiding in sculpt mode. Face sets don't need to be
negative anymore, and a bunch of "face set <-> hide status" conversion
can be removed. Plus some other benefits:
 - We don't need to allocate either array quite as much.
 - The hide status can be read from 1/4 the memory as face sets.
 - Updates when entering or exiting sculpt mode can be removed.
 - More opportunities for early-outs when nothing is hidden.
 - Separating concerns makes sculpt code more obvious.
 - It will be easier to convert face sets into a generic int attribute.

 Differential Revision: https://developer.blender.org/D15950
This commit is contained in:
Hans Goudey 2022-09-14 14:33:55 -05:00
parent 68589a31eb
commit ee23f0f3fb
Notes: blender-bot 2023-03-24 17:05:22 +01:00
Referenced by issue #101116, Regression: Multires levels not visible when entering sculpt mode
Referenced by issue #101097, Sculpt: Initialize Face Sets by Face Set Boundaries not working properly
18 changed files with 166 additions and 328 deletions

View File

@ -529,13 +529,16 @@ typedef struct SculptSession {
/* Mesh Face Sets */
/* Total number of polys of the base mesh. */
int totfaces;
/* Face sets store its visibility in the sign of the integer, using the absolute value as the
* Face Set ID. Positive IDs are visible, negative IDs are hidden.
* The 0 ID is not used by the tools or the visibility system, it is just used when creating new
/* The 0 ID is not used by the tools or the visibility system, it is just used when creating new
* geometry (the trim tool, for example) to detect which geometry was just added, so it can be
* assigned a valid Face Set after creation. Tools are not intended to run with Face Sets IDs set
* to 0. */
int *face_sets;
/**
* A reference to the ".hide_poly" attribute, to store whether (base) polygons are hidden.
* May be null.
*/
bool *hide_poly;
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
@ -697,6 +700,12 @@ 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);
/**
* Create the attribute used to store face visibility and retrieve its data.
* Note that changes to the face visibility have to be propagated to other domains
* (see #SCULPT_visibility_sync_all_from_faces).
*/
bool *BKE_sculpt_hide_poly_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);
@ -704,31 +713,7 @@ struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct O
void BKE_sculpt_bvh_update_from_ccg(struct PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
/**
* This ensure that all elements in the mesh (both vertices and grids) have their visibility
* updated according to the face sets.
*/
void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg);
/**
* Individual function to sync the Face Set visibility to mesh and grids.
*/
void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(struct Mesh *mesh);
void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh,
struct SubdivCCG *subdiv_ccg);
/**
* If a face set layer exists, initialize its visibility (sign) from the mesh's hidden values.
*/
void BKE_sculpt_face_sets_update_from_base_mesh_visibility(struct Mesh *mesh);
/**
* 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 Object *object);
void BKE_sculpt_sync_face_visibility_to_grids(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg);
/**
* Test if PBVH can be used directly for drawing, which is faster than

View File

@ -380,8 +380,6 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int totgrid,
int gridsize);
void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh);
/**
* Multi-res level, only valid for type == #PBVH_GRIDS.
*/

View File

@ -325,6 +325,7 @@ const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG *subdiv_ccg);
const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG *subdiv_ccg);
void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG *subdiv_ccg, int grid_index);
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG *subdiv_ccg, int grid_index);
#ifdef __cplusplus
}

View File

@ -1712,6 +1712,8 @@ static void sculpt_update_object(
ss->face_sets = nullptr;
}
ss->hide_poly = (bool *)CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly");
ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
@ -1720,6 +1722,7 @@ static void sculpt_update_object(
BKE_pbvh_subdiv_cgg_set(ss->pbvh, ss->subdiv_ccg);
BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets);
BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh);
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
@ -1940,29 +1943,21 @@ int *BKE_sculpt_face_sets_ensure(Mesh *mesh)
&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 = -2;
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;
}
}
face_sets.fill(1);
mesh->face_sets_color_default = 1;
return face_sets.data();
}
bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
{
if (bool *hide_poly = static_cast<bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly"))) {
return hide_poly;
}
return static_cast<bool *>(CustomData_add_layer_named(
&mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly"));
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
{
Mesh *me = static_cast<Mesh *>(ob->data);
@ -2082,11 +2077,11 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
return deformed;
}
void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh)
void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
{
using namespace blender;
using namespace blender::bke;
if (!CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) {
if (!subdiv_ccg) {
return;
}
@ -2094,70 +2089,19 @@ void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh)
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()) {
/* Nothing is hidden, so we can just remove all visibility bitmaps. */
for (const int i : hide_poly.index_range()) {
BKE_subdiv_ccg_grid_hidden_free(subdiv_ccg, i);
}
return;
}
MutableSpan<int> face_sets{
static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)), mesh->totpoly};
for (const int i : hide_poly.index_range()) {
face_sets[i] = hide_poly[i] ? -std::abs(face_sets[i]) : std::abs(face_sets[i]);
}
}
static void set_hide_poly_from_face_sets(Mesh &mesh)
{
using namespace blender;
using namespace blender::bke;
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;
}
SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>(
".hide_poly", ATTR_DOMAIN_FACE);
if (!hide_poly) {
return;
}
for (const int i : hide_poly.span.index_range()) {
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);
}
void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
{
const int *face_sets = static_cast<const int *>(
CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS));
if (!face_sets) {
return;
}
if (!subdiv_ccg) {
return;
}
const VArraySpan<bool> hide_poly_span(hide_poly);
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
for (int i = 0; i < mesh->totloop; i++) {
const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, i);
const bool is_hidden = (face_sets[face_index] < 0);
const bool is_hidden = hide_poly_span[face_index];
/* Avoid creating and modifying the grid_hidden bitmap if the base mesh face is visible and
* there is not bitmap for the grid. This is because missing grid_hidden implies grid is fully
@ -2173,41 +2117,6 @@ 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_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(Object *object)
{
Mesh *mesh = BKE_mesh_from_object(object);
BLI_assert(object->mode == OB_MODE_SCULPT);
/* Copy the current mesh visibility to the Face Sets. */
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_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_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:
* + Differences of subdiv levels between sculpt and object modes
* (`mmd->sculptlvl != mmd->lvl`).
* + Addition of a `CD_GRID_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`).
*/
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
}
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
{
PBVH *pbvh = BKE_pbvh_new();
@ -2239,8 +2148,6 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
BKE_mesh_recalc_looptri(
loops.data(), polys.data(), verts.data(), me->totloop, me->totpoly, looptri);
BKE_sculpt_sync_face_set_visibility(me, nullptr);
BKE_pbvh_build_mesh(pbvh,
me,
polys.data(),
@ -2275,7 +2182,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
Mesh *base_mesh = BKE_mesh_from_object(ob);
BKE_sculpt_sync_face_set_visibility(base_mesh, subdiv_ccg);
BKE_sculpt_sync_face_visibility_to_grids(base_mesh, subdiv_ccg);
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
@ -2369,10 +2276,10 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d)
void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uchar r_color[4])
{
float rgba[4];
float random_mod_hue = GOLDEN_RATIO_CONJUGATE * (abs(face_set) + (seed % 10));
float random_mod_hue = GOLDEN_RATIO_CONJUGATE * (face_set + (seed % 10));
random_mod_hue = random_mod_hue - floorf(random_mod_hue);
const float random_mod_sat = BLI_hash_int_01(abs(face_set) + seed + 1);
const float random_mod_val = BLI_hash_int_01(abs(face_set) + seed + 2);
const float random_mod_sat = BLI_hash_int_01(face_set + seed + 1);
const float random_mod_val = BLI_hash_int_01(face_set + seed + 2);
hsv_to_rgb(random_mod_hue,
0.6f + (random_mod_sat * 0.25f),
1.0f - (random_mod_val * 0.35f),

View File

@ -366,26 +366,6 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
return totquad;
}
void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh)
{
const int gridsize = pbvh->gridkey.grid_size;
for (int i = 0; i < pbvh->totgrid; i++) {
BLI_bitmap *gh = pbvh->grid_hidden[i];
const int face_index = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i);
if (!gh && pbvh->face_sets[face_index] < 0) {
gh = pbvh->grid_hidden[i] = BLI_BITMAP_NEW(pbvh->gridkey.grid_area,
"partialvis_update_grids");
}
if (gh) {
for (int y = 0; y < gridsize; y++) {
for (int x = 0; x < gridsize; x++) {
BLI_BITMAP_SET(gh, y * gridsize + x, pbvh->face_sets[face_index] < 0);
}
}
}
}
}
static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
{
int totquads = BKE_pbvh_count_grid_quads(
@ -3218,7 +3198,7 @@ const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh)
const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh)
{
BLI_assert(pbvh->header.type == PBVH_FACES);
BLI_assert(ELEM(pbvh->header.type, PBVH_FACES, PBVH_GRIDS));
return pbvh->hide_poly;
}

View File

@ -2043,6 +2043,11 @@ void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG *subdiv_ccg, int grid_index)
subdiv_ccg->grid_hidden[grid_index] = BLI_BITMAP_NEW(key.grid_area, __func__);
}
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG *subdiv_ccg, int grid_index)
{
MEM_SAFE_FREE(subdiv_ccg->grid_hidden[grid_index]);
}
static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
int *r_ptex_face_index,

View File

@ -3368,5 +3368,15 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
FOREACH_NODETREE_END;
}
/* Face sets no longer store whether the corresponding face is hidden. */
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
int *face_sets = (int *)CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
if (face_sets) {
for (int i = 0; i < mesh->totpoly; i++) {
face_sets[i] = abs(face_sets[i]);
}
}
}
}
}

View File

@ -317,15 +317,10 @@ static void mesh_join_offset_face_sets_ID(const Mesh *mesh, int *face_set_offset
for (int f = 0; f < mesh->totpoly; f++) {
/* As face sets encode the visibility in the integer sign, the offset needs to be added or
* subtracted depending on the initial sign of the integer to get the new ID. */
if (abs(face_sets[f]) <= *face_set_offset) {
if (face_sets[f] > 0) {
face_sets[f] += *face_set_offset;
}
else {
face_sets[f] -= *face_set_offset;
}
if (face_sets[f] <= *face_set_offset) {
face_sets[f] += *face_set_offset;
}
max_face_set = max_ii(max_face_set, abs(face_sets[f]));
max_face_set = max_ii(max_face_set, face_sets[f]);
}
*face_set_offset = max_face_set;
}

View File

@ -186,7 +186,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
if (ob->mode == OB_MODE_SCULPT) {
BKE_sculpt_ensure_orig_mesh_data(ob);
ED_sculpt_undo_geometry_end(ob);
}
@ -912,7 +911,6 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
}
if (ob->mode == OB_MODE_SCULPT) {
BKE_sculpt_ensure_orig_mesh_data(ob);
ED_sculpt_undo_geometry_end(ob);
}

View File

@ -386,8 +386,6 @@ static int hide_show_exec(bContext *C, wmOperator *op)
BKE_pbvh_update_hide_attributes_from_mesh(pbvh);
}
SCULPT_visibility_sync_all_vertex_to_face_sets(ob->sculpt);
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
ED_region_tag_redraw(region);

View File

@ -390,19 +390,15 @@ 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);
BLI_assert(ss->hide_poly != NULL);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
for (int i = 0; i < ss->totfaces; i++) {
if (abs(ss->face_sets[i]) != face_set) {
if (ss->face_sets[i] != face_set) {
continue;
}
if (visible) {
ss->face_sets[i] = abs(ss->face_sets[i]);
}
else {
ss->face_sets[i] = -abs(ss->face_sets[i]);
}
ss->hide_poly[i] = !visible;
}
break;
case PBVH_BMESH:
@ -410,14 +406,15 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl
}
}
void SCULPT_face_sets_visibility_invert(SculptSession *ss)
void SCULPT_face_visibility_all_invert(SculptSession *ss)
{
BLI_assert(ss->face_sets != NULL);
BLI_assert(ss->hide_poly != NULL);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
for (int i = 0; i < ss->totfaces; i++) {
ss->face_sets[i] *= -1;
ss->hide_poly[i] = !ss->hide_poly[i];
}
break;
case PBVH_BMESH:
@ -425,47 +422,29 @@ void SCULPT_face_sets_visibility_invert(SculptSession *ss)
}
}
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
void SCULPT_face_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
* modify the visibility. Force that geometry to the ID 1 to enable changing the visibility
* here. */
if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
ss->face_sets[i] = 1;
}
if (visible) {
ss->face_sets[i] = abs(ss->face_sets[i]);
}
else {
ss->face_sets[i] = -abs(ss->face_sets[i]);
}
}
BLI_assert(ss->hide_poly != NULL);
memset(ss->hide_poly, !visible, sizeof(bool) * ss->totfaces);
break;
case PBVH_BMESH:
break;
}
}
bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex)
bool SCULPT_vertex_any_face_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: {
if (!ss->hide_poly) {
return true;
}
MeshElemMap *vert_map = &ss->pmap[vertex.i];
for (int j = 0; j < ss->pmap[vertex.i].count; j++) {
if (!hide_poly[vert_map->indices[j]]) {
if (!ss->hide_poly[vert_map->indices[j]]) {
return true;
}
}
@ -479,17 +458,16 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef verte
return true;
}
bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex)
bool SCULPT_vertex_all_faces_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: {
if (!ss->hide_poly) {
return true;
}
MeshElemMap *vert_map = &ss->pmap[vertex.i];
for (int j = 0; j < ss->pmap[vertex.i].count; j++) {
if (hide_poly[vert_map->indices[j]]) {
if (ss->hide_poly[vert_map->indices[j]]) {
return false;
}
}
@ -498,10 +476,13 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRe
case PBVH_BMESH:
return true;
case PBVH_GRIDS: {
if (!ss->hide_poly) {
return true;
}
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 !hide_poly[face_index];
return !ss->hide_poly[face_index];
}
}
return true;
@ -514,11 +495,15 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_
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) {
ss->face_sets[vert_map->indices[j]] = abs(face_set);
const int poly_index = vert_map->indices[j];
if (ss->hide_poly && ss->hide_poly[poly_index]) {
/* Skip hidden faces conntected to the vertex. */
continue;
}
ss->face_sets[poly_index] = face_set;
}
} break;
break;
}
case PBVH_BMESH:
break;
case PBVH_GRIDS: {
@ -526,11 +511,13 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_
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);
if (ss->face_sets[face_index] > 0) {
ss->face_sets[face_index] = abs(face_set);
if (ss->hide_poly && ss->hide_poly[face_index]) {
/* Skip the vertex if it's in a hidden face. */
return;
}
} break;
ss->face_sets[face_index] = face_set;
break;
}
}
}
@ -595,19 +582,23 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_
return true;
}
void SCULPT_visibility_sync_all_face_sets_to_verts(Object *ob)
void SCULPT_visibility_sync_all_from_faces(Object *ob)
{
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh);
/* We may have adjusted the ".hide_poly" attribute, now make the hide status attributes for
* vertices and edges consistent. */
BKE_mesh_flush_hidden_from_polys(mesh);
BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh);
break;
}
case PBVH_GRIDS: {
BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh);
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, ss->subdiv_ccg);
/* In addition to making the hide status of the base mesh consistent, we also have to
* propagate the status to the Multires grids. */
BKE_mesh_flush_hidden_from_polys(mesh);
BKE_sculpt_sync_face_visibility_to_grids(mesh, ss->subdiv_ccg);
break;
}
case PBVH_BMESH:
@ -615,46 +606,6 @@ void SCULPT_visibility_sync_all_face_sets_to_verts(Object *ob)
}
}
static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss,
PBVHVertRef vertex)
{
MeshElemMap *vert_map = &ss->pmap[vertex.i];
const bool visible = SCULPT_vertex_visible_get(ss, vertex);
for (int i = 0; i < ss->pmap[vertex.i].count; i++) {
if (visible) {
ss->face_sets[vert_map->indices[i]] = abs(ss->face_sets[vert_map->indices[i]]);
}
else {
ss->face_sets[vert_map->indices[i]] = -abs(ss->face_sets[vert_map->indices[i]]);
}
}
}
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;
for (int l = 0; l < poly->totloop; l++) {
const MLoop *loop = &ss->mloop[poly->loopstart + l];
if (!SCULPT_vertex_visible_get(ss, BKE_pbvh_make_vref(loop->v))) {
poly_visible = false;
}
}
if (poly_visible) {
ss->face_sets[i] = abs(ss->face_sets[i]);
}
else {
ss->face_sets[i] = -abs(ss->face_sets[i]);
}
}
}
}
static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index)
{
if (!ss->face_sets) {
@ -664,10 +615,10 @@ static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int ind
int face_set = -1;
for (int i = 0; i < ss->pmap[index].count; i++) {
if (face_set == -1) {
face_set = abs(ss->face_sets[vert_map->indices[i]]);
face_set = ss->face_sets[vert_map->indices[i]];
}
else {
if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) {
if (ss->face_sets[vert_map->indices[i]] != face_set) {
return false;
}
}
@ -751,8 +702,8 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
}
int next_face_set = 0;
for (int i = 0; i < ss->totfaces; i++) {
if (abs(ss->face_sets[i]) > next_face_set) {
next_face_set = abs(ss->face_sets[i]);
if (ss->face_sets[i] > next_face_set) {
next_face_set = ss->face_sets[i];
}
}
next_face_set++;
@ -940,7 +891,7 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (!SCULPT_vertex_all_face_sets_visible_get(ss, vertex)) {
if (!SCULPT_vertex_all_faces_visible_get(ss, vertex)) {
return true;
}
return sculpt_check_boundary_vertex_in_base_mesh(ss, vertex.i);

View File

@ -67,7 +67,7 @@ int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
int next_face_set_id = 0;
for (int i = 0; i < mesh->totpoly; i++) {
next_face_set_id = max_ii(next_face_set_id, abs(face_sets[i]));
next_face_set_id = max_ii(next_face_set_id, face_sets[i]);
}
next_face_set_id++;
@ -135,6 +135,10 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
if (!sculpt_brush_test_sq_fn(&test, poly_center)) {
continue;
}
const bool face_hidden = ss->hide_poly && ss->hide_poly[vert_map->indices[j]];
if (face_hidden) {
continue;
}
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@ -145,8 +149,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.vertex,
thread_id);
if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set);
if (fade > 0.05f) {
ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set;
}
}
}
@ -750,7 +754,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end(ob);
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
SCULPT_visibility_sync_all_face_sets_to_verts(ob);
SCULPT_visibility_sync_all_from_faces(ob);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);
@ -854,10 +858,12 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (!pbvh_has_face_sets(ss->pbvh)) {
if (!ss->face_sets) {
return OPERATOR_CANCELLED;
}
Mesh *mesh = BKE_object_get_original_mesh(ob);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
const int tot_vert = SCULPT_vertex_count_get(ss);
@ -895,37 +901,49 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
}
}
for (int i = 0; i < ss->totfaces; i++) {
if (ss->face_sets[i] <= 0) {
hidden_vertex = true;
break;
if (ss->hide_poly) {
for (int i = 0; i < ss->totfaces; i++) {
if (ss->hide_poly[i]) {
hidden_vertex = true;
break;
}
}
}
ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
if (hidden_vertex) {
SCULPT_face_sets_visibility_all_set(ss, true);
SCULPT_face_visibility_all_set(ss, true);
}
else {
SCULPT_face_sets_visibility_all_set(ss, false);
SCULPT_face_visibility_all_set(ss, false);
SCULPT_face_set_visibility_set(ss, active_face_set, true);
}
}
if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) {
SCULPT_face_sets_visibility_all_set(ss, true);
/* As an optimization, free the hide attribute when making all geometry visible. This allows
* reduced memory usage without manually clearing it later, and allows sculpt operations to
* avoid checking element's hide status. */
CustomData_free_layer_named(&mesh->pdata, ".hide_poly", mesh->totpoly);
ss->hide_poly = NULL;
BKE_pbvh_update_hide_attributes_from_mesh(pbvh);
}
if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
SCULPT_face_sets_visibility_all_set(ss, false);
ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
SCULPT_face_visibility_all_set(ss, false);
SCULPT_face_set_visibility_set(ss, active_face_set, true);
}
if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
SCULPT_face_set_visibility_set(ss, active_face_set, false);
}
if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
SCULPT_face_sets_visibility_invert(ss);
ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
SCULPT_face_visibility_all_invert(ss);
}
/* For modes that use the cursor active vertex, update the rotation origin for viewport
@ -941,7 +959,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
}
/* Sync face sets visibility and vertex visibility. */
SCULPT_visibility_sync_all_face_sets_to_verts(ob);
SCULPT_visibility_sync_all_from_faces(ob);
SCULPT_undo_push_end(ob);
@ -1008,7 +1026,7 @@ static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSE
return OPERATOR_CANCELLED;
}
if (!pbvh_has_face_sets(ss->pbvh)) {
if (!ss->face_sets) {
return OPERATOR_CANCELLED;
}
@ -1172,14 +1190,15 @@ static bool check_single_face_set(SculptSession *ss, int *face_sets, const bool
int first_face_set = SCULPT_FACE_SET_NONE;
if (check_visible_only) {
for (int f = 0; f < ss->totfaces; f++) {
if (face_sets[f] > 0) {
first_face_set = face_sets[f];
break;
if (ss->hide_poly && ss->hide_poly[f]) {
continue;
}
first_face_set = face_sets[f];
break;
}
}
else {
first_face_set = abs(face_sets[0]);
first_face_set = face_sets[0];
}
if (first_face_set == SCULPT_FACE_SET_NONE) {
@ -1187,8 +1206,10 @@ static bool check_single_face_set(SculptSession *ss, int *face_sets, const bool
}
for (int f = 0; f < ss->totfaces; f++) {
const int face_set_id = check_visible_only ? face_sets[f] : abs(face_sets[f]);
if (face_set_id != first_face_set) {
if (check_visible_only && ss->hide_poly && ss->hide_poly[f]) {
continue;
}
if (face_sets[f] != first_face_set) {
return false;
}
}
@ -1222,9 +1243,10 @@ static void sculpt_face_set_delete_geometry(Object *ob,
BMFace *f;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
const int face_index = BM_elem_index_get(f);
const int face_set_id = modify_hidden ? abs(ss->face_sets[face_index]) :
ss->face_sets[face_index];
BM_elem_flag_set(f, BM_ELEM_TAG, face_set_id == active_face_set_id);
if (!modify_hidden && ss->hide_poly && ss->hide_poly[face_index]) {
continue;
}
BM_elem_flag_set(f, BM_ELEM_TAG, ss->face_sets[face_index] == active_face_set_id);
}
BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
@ -1353,7 +1375,7 @@ static void face_set_edit_do_post_visibility_updates(Object *ob, PBVHNode **node
PBVH *pbvh = ss->pbvh;
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
SCULPT_visibility_sync_all_face_sets_to_verts(ob);
SCULPT_visibility_sync_all_from_faces(ob);
for (int i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_update_visibility(nodes[i]);

View File

@ -170,8 +170,6 @@ 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;
@ -201,7 +199,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 (hide_poly && hide_poly[poly]) {
if (ss->hide_poly && ss->hide_poly[poly]) {
continue;
}
const MPoly *mpoly = &polys[poly];

View File

@ -1004,9 +1004,13 @@ void SCULPT_connected_components_ensure(Object *ob);
void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible);
bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex);
bool SCULPT_vertex_all_faces_visible_get(const SculptSession *ss, PBVHVertRef vertex);
bool SCULPT_vertex_any_face_visible_get(SculptSession *ss, PBVHVertRef vertex);
void SCULPT_visibility_sync_all_face_sets_to_verts(struct Object *ob);
void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
void SCULPT_face_visibility_all_invert(SculptSession *ss);
void SCULPT_face_visibility_all_set(SculptSession *ss, bool visible);
void SCULPT_visibility_sync_all_from_faces(struct Object *ob);
/** \} */
@ -1024,11 +1028,6 @@ bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex);
int SCULPT_face_set_next_available_get(SculptSession *ss);
void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex);
bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex);
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
/** \} */

View File

@ -300,8 +300,6 @@ 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(ob);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
/* This function expects a fully evaluated depsgraph. */

View File

@ -767,7 +767,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask, false);
SCULPT_visibility_sync_all_face_sets_to_verts(ob);
SCULPT_visibility_sync_all_from_faces(ob);
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
@ -923,7 +923,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
if (update_visibility) {
SCULPT_visibility_sync_all_vertex_to_face_sets(ss);
BKE_pbvh_update_visibility(ss->pbvh);
}

View File

@ -406,7 +406,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (show_face_sets) {
const int fset = abs(sculpt_face_sets[lt->poly]);
const int fset = sculpt_face_sets[lt->poly];
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
@ -766,7 +766,7 @@ void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
if (show_face_sets && subdiv_ccg && sculpt_face_sets) {
const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid_index);
const int fset = abs(sculpt_face_sets[face_index]);
const int fset = sculpt_face_sets[face_index];
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);

View File

@ -497,12 +497,6 @@ static void rna_Object_dependency_update(Main *bmain, Scene *UNUSED(scene), Poin
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(object);
}
rna_Object_internal_update_data_dependency(bmain, scene, ptr);
}