diff --git a/source/blender/blenkernel/BKE_bvhutils.hh b/source/blender/blenkernel/BKE_bvhutils.hh index 80de92dc24e..076e28faefe 100644 --- a/source/blender/blenkernel/BKE_bvhutils.hh +++ b/source/blender/blenkernel/BKE_bvhutils.hh @@ -55,6 +55,12 @@ enum BVHCacheType { BVHTREE_FROM_LOOSEVERTS, BVHTREE_FROM_LOOSEEDGES, + /* These types consider geometry visibility when getting loose elements. + * NOTE: If the element is linked to a face or edge that is hidden, but the element itself is not + * hidden, it is considered a loose element. */ + BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN, + BVHTREE_FROM_LOOSEEDGES_NO_HIDDEN, + /* Keep `BVHTREE_MAX_ITEM` as last item. */ BVHTREE_MAX_ITEM, }; diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index be24b3c4771..08af4a4509d 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -509,14 +509,15 @@ static void bvhtree_from_mesh_setup_data(BVHTree *tree, switch (bvh_cache_type) { case BVHTREE_FROM_VERTS: case BVHTREE_FROM_LOOSEVERTS: + case BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN: /* a nullptr nearest callback works fine * remember the min distance to point is the same as the min distance to BV of point */ r_data->nearest_callback = nullptr; r_data->raycast_callback = mesh_verts_spherecast; break; - case BVHTREE_FROM_EDGES: case BVHTREE_FROM_LOOSEEDGES: + case BVHTREE_FROM_LOOSEEDGES_NO_HIDDEN: r_data->nearest_callback = mesh_edges_nearest_point; r_data->raycast_callback = mesh_edges_spherecast; break; @@ -780,6 +781,89 @@ BVHTree *bvhtree_from_mesh_corner_tris_ex(BVHTreeFromMesh *data, return tree; } +static BitVector<> loose_verts_no_hidden_mask_get(const Mesh &mesh, int *r_elem_active_len) +{ + using namespace blender; + using namespace blender::bke; + + int count = mesh.verts_num; + BitVector<> verts_mask(count, true); + + const AttributeAccessor attributes = mesh.attributes(); + const Span edges = mesh.edges(); + const VArray hide_edge = *attributes.lookup_or_default( + ".hide_edge", AttrDomain::Edge, false); + const VArray hide_vert = *attributes.lookup_or_default( + ".hide_vert", AttrDomain::Point, false); + + for (const int i : edges.index_range()) { + if (hide_edge[i]) { + continue; + } + for (const int vert : {edges[i][0], edges[i][1]}) { + if (verts_mask[vert]) { + verts_mask[vert].reset(); + count--; + } + } + } + + if (count) { + for (const int vert : verts_mask.index_range()) { + if (verts_mask[vert] && hide_vert[vert]) { + verts_mask[vert].reset(); + count--; + } + } + } + + *r_elem_active_len = count; + + return verts_mask; +} + +static BitVector<> loose_edges_no_hidden_mask_get(const Mesh &mesh, int *r_elem_active_len) +{ + using namespace blender; + using namespace blender::bke; + + int count = mesh.edges_num; + BitVector<> edge_mask(count, true); + + const AttributeAccessor attributes = mesh.attributes(); + const OffsetIndices faces = mesh.faces(); + const Span corner_edges = mesh.corner_edges(); + const VArray hide_poly = *attributes.lookup_or_default( + ".hide_poly", AttrDomain::Face, false); + const VArray hide_edge = *attributes.lookup_or_default( + ".hide_edge", AttrDomain::Edge, false); + + for (const int i : faces.index_range()) { + if (hide_poly[i]) { + continue; + } + for (const int edge : corner_edges.slice(faces[i])) { + if (edge_mask[edge]) { + edge_mask[edge].reset(); + count--; + } + } + } + + if (count) { + for (const int edge : edge_mask.index_range()) { + if (edge_mask[edge] && hide_edge[edge]) { + edge_mask[edge].reset(); + count--; + } + } + } + + *r_elem_active_len = count; + + return edge_mask; +} + static BitVector<> corner_tris_no_hidden_map_get(const blender::OffsetIndices faces, const VArray &hide_poly, const int corner_tris_len, @@ -860,6 +944,13 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data, 0.0f, tree_type, 6, positions, loose_verts.is_loose_bits, loose_verts.count); break; } + case BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN: { + int mask_bits_act_len = -1; + const BitVector<> mask = loose_verts_no_hidden_mask_get(*mesh, &mask_bits_act_len); + data->tree = bvhtree_from_mesh_verts_create_tree( + 0.0f, tree_type, 6, positions, mask, mask_bits_act_len); + break; + } case BVHTREE_FROM_VERTS: { data->tree = bvhtree_from_mesh_verts_create_tree(0.0f, tree_type, 6, positions, {}, -1); break; @@ -870,6 +961,13 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data, positions, edges, loose_edges.is_loose_bits, loose_edges.count, 0.0f, tree_type, 6); break; } + case BVHTREE_FROM_LOOSEEDGES_NO_HIDDEN: { + int mask_bits_act_len = -1; + const BitVector<> mask = loose_edges_no_hidden_mask_get(*mesh, &mask_bits_act_len); + data->tree = bvhtree_from_mesh_edges_create_tree( + positions, edges, mask, mask_bits_act_len, 0.0f, tree_type, 6); + break; + } case BVHTREE_FROM_EDGES: { data->tree = bvhtree_from_mesh_edges_create_tree( positions, edges, {}, -1, 0.0f, tree_type, 6); diff --git a/source/blender/editors/transform/transform_snap_object.hh b/source/blender/editors/transform/transform_snap_object.hh index 34fccff1559..deecb55effa 100644 --- a/source/blender/editors/transform/transform_snap_object.hh +++ b/source/blender/editors/transform/transform_snap_object.hh @@ -227,7 +227,7 @@ eSnapMode snap_object_mesh(SnapObjectContext *sctx, const ID *id, const blender::float4x4 &obmat, eSnapMode snap_to_flag, - bool use_hide); + bool skip_hidden); eSnapMode snap_polygon_mesh(SnapObjectContext *sctx, const Object *ob_eval, diff --git a/source/blender/editors/transform/transform_snap_object_mesh.cc b/source/blender/editors/transform/transform_snap_object_mesh.cc index 6049f54c807..a8df25c83d5 100644 --- a/source/blender/editors/transform/transform_snap_object_mesh.cc +++ b/source/blender/editors/transform/transform_snap_object_mesh.cc @@ -29,14 +29,14 @@ using namespace blender; * \{ */ static void snap_object_data_mesh_get(const Mesh *mesh_eval, - bool use_hide, + bool skip_hidden, BVHTreeFromMesh *r_treedata) { /* The BVHTree from corner_tris is always required. */ BKE_bvhtree_from_mesh_get(r_treedata, mesh_eval, - use_hide ? BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN : - BVHTREE_FROM_CORNER_TRIS, + skip_hidden ? BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN : + BVHTREE_FROM_CORNER_TRIS, 4); } @@ -424,9 +424,13 @@ eSnapMode snap_edge_points_mesh(SnapObjectContext *sctx, return elem; } -static eSnapMode mesh_snap_mode_supported(const Mesh *mesh) +static eSnapMode mesh_snap_mode_supported(const Mesh *mesh, bool skip_hidden) { - eSnapMode snap_mode_supported = mesh->loose_verts().count ? SCE_SNAP_TO_POINT : SCE_SNAP_TO_NONE; + /* When skipping hidden geometry, we still cannot obtain the number of loose verts + * until computing #BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN. Therefore, consider #SCE_SNAP_TO_POINT + * supported even if the mesh has no loose vertices in this case. */ + eSnapMode snap_mode_supported = (skip_hidden || mesh->loose_verts().count) ? SCE_SNAP_TO_POINT : + SCE_SNAP_TO_NONE; if (mesh->faces_num) { snap_mode_supported |= SCE_SNAP_TO_FACE | SCE_SNAP_INDIVIDUAL_NEAREST | SNAP_TO_EDGE_ELEMENTS; } @@ -441,7 +445,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, - bool use_hide, + bool skip_hidden, eSnapMode snap_to) { BLI_assert(snap_to != SCE_SNAP_TO_FACE); @@ -455,19 +459,28 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, } } - snap_to &= mesh_snap_mode_supported(mesh_eval) & (SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT); + snap_to &= mesh_snap_mode_supported(mesh_eval, skip_hidden) & + (SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT); if (snap_to == SCE_SNAP_TO_NONE) { return SCE_SNAP_TO_NONE; } BVHTreeFromMesh treedata, treedata_dummy; - snap_object_data_mesh_get(mesh_eval, use_hide, &treedata); + snap_object_data_mesh_get(mesh_eval, skip_hidden, &treedata); BVHTree *bvhtree[2] = {nullptr}; - bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, mesh_eval, BVHTREE_FROM_LOOSEEDGES, 2); + bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, + mesh_eval, + skip_hidden ? BVHTREE_FROM_LOOSEEDGES_NO_HIDDEN : + BVHTREE_FROM_LOOSEEDGES, + 2); BLI_assert(treedata_dummy.cached); if (snap_to & SCE_SNAP_TO_POINT) { - bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy, mesh_eval, BVHTREE_FROM_LOOSEVERTS, 2); + bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy, + mesh_eval, + skip_hidden ? BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN : + BVHTREE_FROM_LOOSEVERTS, + 2); BLI_assert(treedata_dummy.cached); } @@ -583,26 +596,26 @@ eSnapMode snap_object_mesh(SnapObjectContext *sctx, const ID *id, const float4x4 &obmat, eSnapMode snap_to_flag, - bool use_hide) + bool skip_hidden) { eSnapMode elem = SCE_SNAP_TO_NONE; const Mesh *mesh_eval = reinterpret_cast(id); if (snap_to_flag & (SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT)) { - elem = snapMesh(sctx, ob_eval, mesh_eval, obmat, use_hide, snap_to_flag); + elem = snapMesh(sctx, ob_eval, mesh_eval, obmat, skip_hidden, snap_to_flag); if (elem) { return elem; } } if (snap_to_flag & SCE_SNAP_TO_FACE) { - if (raycastMesh(sctx, ob_eval, mesh_eval, obmat, sctx->runtime.object_index++, use_hide)) { + if (raycastMesh(sctx, ob_eval, mesh_eval, obmat, sctx->runtime.object_index++, skip_hidden)) { return SCE_SNAP_TO_FACE; } } if (snap_to_flag & SCE_SNAP_INDIVIDUAL_NEAREST) { - if (nearest_world_mesh(sctx, ob_eval, mesh_eval, obmat, use_hide)) { + if (nearest_world_mesh(sctx, ob_eval, mesh_eval, obmat, skip_hidden)) { return SCE_SNAP_INDIVIDUAL_NEAREST; } }