From 50e6d56e4e4214c3cff5fdef7a1014736a8aa9dd Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Fri, 31 Jul 2020 00:27:53 +0200 Subject: [PATCH 1/2] Fix missing duplicates in the subdiv_ccg neighbors function Duplicates of a grid corner adjacent to an edge which are on the adjacent grid of the same face were not added when requested. Needed for D8356 to work, it may also fix some other bug in Multires. Reviewed By: sergey Differential Revision: https://developer.blender.org/D8385 --- source/blender/blenkernel/intern/subdiv_ccg.c | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 22649a2af07..11d5df4f672 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -1618,6 +1618,18 @@ static int prev_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int return point_index - 1; } +/* When the point index corresponds to a grid corner, returs the point index which corresponds to + * the corner of the adjacent grid, as the adjacent edge has two separate points for each grid + * corner at the middle of the edge. */ +static int adjacent_grid_corner_point_index_on_edge(const SubdivCCG *subdiv_ccg, + const int point_index) +{ + if (point_index == subdiv_ccg->grid_size) { + return point_index - 1; + } + return point_index + 1; +} + /* Common implementation of neighbor calculation when input coordinate is at the edge between two * coarse faces, but is not at the coarse vertex. */ static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, @@ -1626,6 +1638,7 @@ static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, SubdivCCGNeighbors *r_neighbors) { + const bool is_corner = is_corner_grid_coord(subdiv_ccg, coord); const int adjacent_edge_index = adjacent_edge_index_from_coord(subdiv_ccg, coord); BLI_assert(adjacent_edge_index >= 0); BLI_assert(adjacent_edge_index < subdiv_ccg->num_adjacent_edges); @@ -1633,15 +1646,27 @@ static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, /* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */ const int num_adjacent_faces = adjacent_edge->num_adjacent_faces; - subdiv_ccg_neighbors_init( - r_neighbors, num_adjacent_faces + 2, (include_duplicates) ? num_adjacent_faces - 1 : 0); + int num_duplicates = 0; + if (include_duplicates) { + num_duplicates += num_adjacent_faces - 1; + if (is_corner) { + /* When the coord is a grid corner, add an extra duplicate per adajacent grid in all adjacent + * faces to the edge. */ + num_duplicates += num_adjacent_faces; + } + } + subdiv_ccg_neighbors_init(r_neighbors, num_adjacent_faces + 2, num_duplicates); const int point_index = adjacent_edge_point_index_from_coord( subdiv_ccg, coord, adjacent_edge_index); + const int point_index_duplicate = adjacent_grid_corner_point_index_on_edge(subdiv_ccg, + point_index); + const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index); const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index); - for (int i = 0, duplicate_i = num_adjacent_faces; i < num_adjacent_faces; ++i) { + int duplicate_i = num_adjacent_faces; + for (int i = 0; i < num_adjacent_faces; ++i) { SubdivCCGCoord *boundary_coords = adjacent_edge->boundary_coords[i]; /* One step into the grid from the edge for each adjacent face. */ SubdivCCGCoord grid_coord = boundary_coords[point_index]; @@ -1657,7 +1682,15 @@ static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, r_neighbors->coords[duplicate_i + 2] = grid_coord; duplicate_i++; } + + /* When it is a corner, add the duplicate of the adjacent grid in the same face. */ + if (include_duplicates && is_corner) { + SubdivCCGCoord duplicate_corner_grid_coord = boundary_coords[point_index_duplicate]; + r_neighbors->coords[duplicate_i + 2] = duplicate_corner_grid_coord; + duplicate_i++; + } } + BLI_assert(duplicate_i - num_adjacent_faces == num_duplicates); } /* The corner is at the middle of edge between faces. */ From 3ebe97c06b67d1611dfeaa3919512155416b0378 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Mon, 27 Jul 2020 23:40:19 +0200 Subject: [PATCH 2/2] Fix T78665: Face Set visibility reverted when chaning Multires Levels Face Sets where only set and updated on the PBVH after starting a sculpt tool. In order to preserve the visibility they store when changing levels, they need to be updated and sync also on PBVH creation Reviewed By: sergey Maniphest Tasks: T78665 Differential Revision: https://developer.blender.org/D8225 --- source/blender/blenkernel/BKE_paint.h | 4 ++ source/blender/blenkernel/BKE_subdiv_ccg.h | 2 + source/blender/blenkernel/intern/paint.c | 64 +++++++++++++++++++ source/blender/blenkernel/intern/subdiv_ccg.c | 11 ++++ 4 files changed, 81 insertions(+) diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 1c02aece06f..de18ec6b792 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -471,6 +471,10 @@ 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); + bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d); enum { diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 5808f223f32..02b83a043b4 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -338,6 +338,8 @@ SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const Subdi 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); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index d6fbba74a89..0ba5ec43318 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1825,6 +1825,64 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc return deformed; } +static void sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +{ + int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + if (!face_sets) { + return; + } + + for (int i = 0; i < mesh->totvert; i++) { + mesh->mvert[i].flag |= ME_HIDE; + } + + for (int i = 0; i < mesh->totpoly; i++) { + if (face_sets[i] >= 0) { + for (int l = 0; l < mesh->mpoly[i].totloop; l++) { + MLoop *loop = &mesh->mloop[mesh->mpoly[i].loopstart + l]; + mesh->mvert[loop->v].flag &= ~ME_HIDE; + } + } + } +} + +static void sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) +{ + int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + if (!face_sets) { + return; + } + + if (!subdiv_ccg) { + return; + } + + 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); + + /* 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 + * visible. */ + if (is_hidden) { + BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg, i); + } + + BLI_bitmap *gh = subdiv_ccg->grid_hidden[i]; + if (gh) { + BLI_bitmap_set_all(gh, is_hidden, key.grid_area); + } + } +} + +void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg) +{ + sculpt_sync_face_sets_visibility_to_base_mesh(mesh); + sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg); +} + static PBVH *build_pbvh_for_dynamic_topology(Object *ob) { PBVH *pbvh = BKE_pbvh_new(); @@ -1850,6 +1908,8 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); + BKE_sculpt_sync_face_set_visibility(me, NULL); + BKE_pbvh_build_mesh(pbvh, me, me->mpoly, @@ -1882,6 +1942,10 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); PBVH *pbvh = BKE_pbvh_new(); 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_pbvh_build_grids(pbvh, subdiv_ccg->grids, subdiv_ccg->num_grids, diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 11d5df4f672..bc1b79f62c5 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -1922,4 +1922,15 @@ SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const Subdi return SUBDIV_CCG_ADJACENT_NONE; } +void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG *subdiv_ccg, int grid_index) +{ + if (subdiv_ccg->grid_hidden[grid_index] != NULL) { + return; + } + + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + subdiv_ccg->grid_hidden[grid_index] = BLI_BITMAP_NEW(key.grid_area, __func__); +} + /** \} */