[Bf-blender-cvs] [caf6225a3d0] master: UV: support uv seams when computing uv islands

Chris Blackbourn noreply at git.blender.org
Mon Sep 12 02:28:21 CEST 2022


Commit: caf6225a3d01b3a5d471dc62bb4508477fc4e7df
Author: Chris Blackbourn
Date:   Mon Sep 12 12:22:46 2022 +1200
Branches: master
https://developer.blender.org/rBcaf6225a3d01b3a5d471dc62bb4508477fc4e7df

UV: support uv seams when computing uv islands

An edge can be marked BM_ELEM_SEAM, which means the UV co-ordinates
on either side of the edge are actually independent, even if they
happen to currently have the same value.

This commit optionally add support for UV Seams when computing islands.

Affects UV sculpt tools, individual origins, UV stitch and changing
UV selection modes etc.

Required for upcoming packing refactor which requires seam support
when computing islands.

Differential Revision: https://developer.blender.org/D15875

===================================================================

M	source/blender/editors/include/ED_mesh.h
M	source/blender/editors/mesh/editmesh_utils.c
M	source/blender/editors/sculpt_paint/sculpt_uv.c
M	source/blender/editors/transform/transform_convert_mesh_uv.c
M	source/blender/editors/uvedit/uvedit_ops.c
M	source/blender/editors/uvedit/uvedit_select.c
M	source/blender/editors/uvedit/uvedit_smart_stitch.c

===================================================================

diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index b6a652bd3ab..26743a2bd08 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -139,6 +139,7 @@ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
                                               const struct Scene *scene,
                                               bool uv_selected,
                                               bool use_winding,
+                                              bool use_seams,
                                               bool do_islands);
 void BM_uv_element_map_free(struct UvElementMap *element_map);
 struct UvElement *BM_uv_element_get(const struct UvElementMap *map,
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index a6a6b095c31..cca2aa11ac3 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -851,10 +851,99 @@ static void bm_uv_build_islands(UvElementMap *element_map,
   MEM_SAFE_FREE(map);
 }
 
+/* return true if `loop` has UV co-ordinates which match `luv_a` and `luv_b` */
+static bool loop_uv_match(BMLoop *loop, MLoopUV *luv_a, MLoopUV *luv_b, int cd_loop_uv_offset)
+{
+  MLoopUV *luv_c = BM_ELEM_CD_GET_VOID_P(loop, cd_loop_uv_offset);
+  MLoopUV *luv_d = BM_ELEM_CD_GET_VOID_P(loop->next, cd_loop_uv_offset);
+  return compare_v2v2(luv_a->uv, luv_c->uv, STD_UV_CONNECT_LIMIT) &&
+         compare_v2v2(luv_b->uv, luv_d->uv, STD_UV_CONNECT_LIMIT);
+}
+
+/* Given `anchor` and `edge`, return true if there are edges that fan between them that are
+ * seam-free. */
+static bool seam_connected_recursive(BMVert *anchor,
+                                     BMEdge *edge,
+                                     MLoopUV *luv_anchor,
+                                     MLoopUV *luv_fan,
+                                     BMLoop *needle,
+                                     GSet *visited,
+                                     int cd_loop_uv_offset)
+{
+  BLI_assert(edge->v1 == anchor || edge->v2 == anchor);
+  BLI_assert(needle->v == anchor || needle->next->v == anchor);
+
+  if (BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
+    return false; /* Edge is a seam, don't traverse. */
+  }
+
+  if (!BLI_gset_add(visited, edge)) {
+    return false; /* Already visited. */
+  }
+
+  BMLoop *loop;
+  BMIter liter;
+  BM_ITER_ELEM (loop, &liter, edge, BM_LOOPS_OF_EDGE) {
+    if (loop->v == anchor) {
+      if (!loop_uv_match(loop, luv_anchor, luv_fan, cd_loop_uv_offset)) {
+        continue; /* `loop` is disjoint in UV space. */
+      }
+
+      if (loop->prev == needle) {
+        return true; /* Success. */
+      }
+
+      MLoopUV *luv_far = BM_ELEM_CD_GET_VOID_P(loop->prev, cd_loop_uv_offset);
+      if (seam_connected_recursive(
+              anchor, loop->prev->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset)) {
+        return true;
+      }
+    }
+    else {
+      BLI_assert(loop->next->v == anchor);
+      if (!loop_uv_match(loop, luv_fan, luv_anchor, cd_loop_uv_offset)) {
+        continue; /* `loop` is disjoint in UV space. */
+      }
+
+      if (loop->next == needle) {
+        return true; /* Success. */
+      }
+
+      MLoopUV *luv_far = BM_ELEM_CD_GET_VOID_P(loop->next->next, cd_loop_uv_offset);
+      if (seam_connected_recursive(
+              anchor, loop->next->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+/* Given `loop_a` and `loop_b` originate from the same vertex and share a UV,
+ * return true if there are edges that fan between them that are seam-free.
+ * return false otherwise.
+ */
+static bool seam_connected(BMLoop *loop_a, BMLoop *loop_b, GSet *visited, int cd_loop_uv_offset)
+{
+  BLI_assert(loop_a && loop_b);
+  BLI_assert(loop_a != loop_b);
+  BLI_assert(loop_a->v == loop_b->v);
+
+  BLI_gset_clear(visited, NULL);
+
+  MLoopUV *luv_anchor = BM_ELEM_CD_GET_VOID_P(loop_a, cd_loop_uv_offset);
+  MLoopUV *luv_fan = BM_ELEM_CD_GET_VOID_P(loop_a->next, cd_loop_uv_offset);
+  const bool result = seam_connected_recursive(
+      loop_a->v, loop_a->e, luv_anchor, luv_fan, loop_b, visited, cd_loop_uv_offset);
+  return result;
+}
+
 UvElementMap *BM_uv_element_map_create(BMesh *bm,
                                        const Scene *scene,
                                        const bool uv_selected,
                                        const bool use_winding,
+                                       const bool use_seams,
                                        const bool do_islands)
 {
   /* In uv sync selection, all UVs are visible. */
@@ -956,6 +1045,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
   }
   BLI_buffer_free(&tf_uv_buf);
 
+  GSet *seam_visited_gset = use_seams ? BLI_gset_ptr_new(__func__) : NULL;
+
   /* For each BMVert, sort associated linked list into unique uvs. */
   int ev_index;
   BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, ev_index) {
@@ -1001,6 +1092,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
                       winding[BM_elem_index_get(v->l->f)];
         }
 
+        if (connected && use_seams) {
+          connected = seam_connected(iterv->l, v->l, seam_visited_gset, cd_loop_uv_offset);
+        }
+
         if (connected) {
           if (lastv) {
             lastv->next = next;
@@ -1026,6 +1121,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
     element_map->vertex[ev_index] = newvlist;
   }
 
+  if (seam_visited_gset) {
+    BLI_gset_free(seam_visited_gset, NULL);
+    seam_visited_gset = NULL;
+  }
   MEM_SAFE_FREE(winding);
 
   /* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 8b9776cf94d..4739fa52674 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -686,9 +686,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
     /* Winding was added to island detection in 5197aa04c6bd
      * However the sculpt tools can flip faces, potentially creating orphaned islands.
      * See T100132 */
-    bool use_winding = false;
+    const bool use_winding = false;
+    const bool use_seams = true;
     data->elementMap = BM_uv_element_map_create(
-        bm, scene, false, use_winding, do_island_optimization);
+        bm, scene, false, use_winding, use_seams, do_island_optimization);
 
     if (!data->elementMap) {
       uv_sculpt_stroke_exit(C, op);
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index f3bef2c283b..27f12137e3a 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -265,7 +265,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
     /* count */
     if (is_island_center) {
       /* create element map with island information */
-      elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true);
+      elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true, true);
       if (elementmap == NULL) {
         continue;
       }
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index c0dd7623ade..4cc2c6450df 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -535,7 +535,7 @@ static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool)
     return false;
   }
 
-  UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true);
+  UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true, true);
   if (element_map == NULL) {
     return false;
   }
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index cecf0ff7914..43c8620df1d 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -5384,7 +5384,7 @@ static void uv_isolate_selected_islands(const Scene *scene,
   BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0);
   BMFace *efa;
   BMIter iter, liter;
-  UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true);
+  UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true, true);
   if (elementmap == NULL) {
     return;
   }
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index e89f99fc412..e19cc67bd16 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1855,7 +1855,7 @@ static StitchState *stitch_init(bContext *C,
    * for stitch this isn't useful behavior, see T86924. */
   const int selectmode_orig = scene->toolsettings->selectmode;
   scene->toolsettings->selectmode = SCE_SELECT_VERTEX;
-  state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true);
+  state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true, true);
   scene->toolsettings->selectmode = selectmode_orig;
 
   if (!state->element_map) {



More information about the Bf-blender-cvs mailing list