[Bf-blender-cvs] [9296ba86746] blender-v2.91-release: Fix T82637: pack UV islands fails with some non-manifold meshes

Campbell Barton noreply at git.blender.org
Tue Nov 17 14:27:10 CET 2020


Commit: 9296ba867462f7ff3c55bc0c9129af4121243bed
Author: Campbell Barton
Date:   Wed Nov 18 00:06:04 2020 +1100
Branches: blender-v2.91-release
https://developer.blender.org/rB9296ba867462f7ff3c55bc0c9129af4121243bed

Fix T82637: pack UV islands fails with some non-manifold meshes

Edges with 3 or more connected UV's caused UV pack to fail.

Instead of using functions from uvedit_parametrizer.c which are intended
specifically for ABF/LSCM unwrapping, use a simpler method for packing
which stores arrays of BMesh faces.

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

M	source/blender/editors/include/ED_uvedit.h
M	source/blender/editors/uvedit/CMakeLists.txt
A	source/blender/editors/uvedit/uvedit_islands.c
M	source/blender/editors/uvedit/uvedit_unwrap_ops.c

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

diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 629e77bd4f2..a55e97fff72 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -27,6 +27,7 @@
 extern "C" {
 #endif
 
+struct ARegion;
 struct ARegionType;
 struct BMEditMesh;
 struct BMFace;
@@ -233,6 +234,20 @@ void ED_image_draw_cursor(struct ARegion *region, const float cursor[2]);
 /* uvedit_buttons.c */
 void ED_uvedit_buttons_register(struct ARegionType *art);
 
+/* uvedit_islands.c */
+struct UVPackIsland_Params {
+  uint rotate : 1;
+  /** -1 not to align to axis, otherwise 0,1 for X,Y. */
+  int rotate_align_axis : 2;
+  uint only_selected_uvs : 1;
+  uint only_selected_faces : 1;
+  uint correct_aspect : 1;
+};
+void ED_uvedit_pack_islands_multi(const Scene *scene,
+                                  Object **objects,
+                                  const uint objects_len,
+                                  const struct UVPackIsland_Params *params);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index f1751ef8d27..8e4a3df920e 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -39,6 +39,7 @@ set(SRC
   uvedit_parametrizer.c
   uvedit_path.c
   uvedit_rip.c
+  uvedit_islands.c
   uvedit_select.c
   uvedit_smart_stitch.c
   uvedit_unwrap_ops.c
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
new file mode 100644
index 00000000000..ddca05bedc5
--- /dev/null
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -0,0 +1,485 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup eduv
+ *
+ * Utilities for manipulating UV islands.
+ *
+ * \note This is similar to `uvedit_parametrizer.c`,
+ * however the data structures there don't support arbitrary topology
+ * such as an edge with 3 or more faces using it.
+ * This API uses #BMesh data structures and doesn't have limitations for manifold meshes.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_boxpack_2d.h"
+#include "BLI_convexhull_2d.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_uvedit.h" /* Own include. */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "bmesh.h"
+
+/* -------------------------------------------------------------------- */
+/** \name UV Face Utilities
+ * \{ */
+
+static void bm_face_uv_scale_y(BMFace *f, const float scale_y, const int cd_loop_uv_offset)
+{
+  BMLoop *l_iter;
+  BMLoop *l_first;
+  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+  do {
+    MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+    luv->uv[1] *= scale_y;
+  } while ((l_iter = l_iter->next) != l_first);
+}
+
+static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f,
+                                                        const float offset[2],
+                                                        const float scale[2],
+                                                        const float pivot[2],
+                                                        const int cd_loop_uv_offset)
+{
+  BMLoop *l_iter;
+  BMLoop *l_first;
+  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+  do {
+    MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+    for (int i = 0; i < 2; i++) {
+      luv->uv[i] = offset[i] + (((luv->uv[i] - pivot[i]) * scale[i]) + pivot[i]);
+    }
+  } while ((l_iter = l_iter->next) != l_first);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Face Array Utilities
+ * \{ */
+
+static void bm_face_array_calc_bounds(BMFace **faces,
+                                      int faces_len,
+                                      const uint cd_loop_uv_offset,
+                                      rctf *r_bounds_rect)
+{
+  float bounds_min[2], bounds_max[2];
+  INIT_MINMAX2(bounds_min, bounds_max);
+  for (int i = 0; i < faces_len; i++) {
+    BMFace *f = faces[i];
+    BM_face_uv_minmax(f, bounds_min, bounds_max, cd_loop_uv_offset);
+  }
+  r_bounds_rect->xmin = bounds_min[0];
+  r_bounds_rect->ymin = bounds_min[1];
+  r_bounds_rect->xmax = bounds_max[0];
+  r_bounds_rect->ymax = bounds_max[1];
+}
+
+/**
+ * Return an array of un-ordered UV coordinates,
+ * without duplicating coordinates for loops that share a vertex.
+ */
+static float (*bm_face_array_calc_unique_uv_coords(
+    BMFace **faces, int faces_len, const uint cd_loop_uv_offset, int *r_coords_len))[2]
+{
+  int coords_len_alloc = 0;
+  for (int i = 0; i < faces_len; i++) {
+    BMFace *f = faces[i];
+    BMLoop *l_iter, *l_first;
+    l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+    do {
+      BM_elem_flag_enable(l_iter, BM_ELEM_TAG);
+    } while ((l_iter = l_iter->next) != l_first);
+    coords_len_alloc += f->len;
+  }
+
+  float(*coords)[2] = MEM_mallocN(sizeof(*coords) * coords_len_alloc, __func__);
+  int coords_len = 0;
+
+  for (int i = 0; i < faces_len; i++) {
+    BMFace *f = faces[i];
+    BMLoop *l_iter, *l_first;
+    l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+    do {
+      if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
+        /* Already walked over, continue. */
+        continue;
+      }
+
+      BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
+      const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+      copy_v2_v2(coords[coords_len++], luv->uv);
+
+      /* Un tag all connected so we don't add them twice.
+       * Note that we will tag other loops not part of `faces` but this is harmless,
+       * since we're only turning off a tag. */
+      BMVert *v_pivot = l_iter->v;
+      BMEdge *e_first = v_pivot->e;
+      const BMEdge *e = e_first;
+      do {
+        const BMLoop *l_radial = e->l;
+        do {
+          if (l_radial->v == l_iter->v) {
+            if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) {
+              const MLoopUV *luv_radial = BM_ELEM_CD_GET_VOID_P(l_radial, cd_loop_uv_offset);
+              if (equals_v2v2(luv->uv, luv_radial->uv)) {
+                /* Don't add this UV when met in another face in `faces`. */
+                BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
+              }
+            }
+          }
+        } while ((l_radial = l_radial->radial_next) != e->l);
+      } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != e_first);
+    } while ((l_iter = l_iter->next) != l_first);
+  }
+  coords = MEM_reallocN(coords, sizeof(*coords) * coords_len);
+  *r_coords_len = coords_len;
+  return coords;
+}
+
+/**
+ * \param align_to_axis:
+ * - -1: don't align to an axis.
+ * -  0: align horizontally.
+ * -  1: align vertically.
+ */
+static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces,
+                                             int faces_len,
+                                             int align_to_axis,
+                                             const uint cd_loop_uv_offset)
+{
+  /* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */
+  int coords_len;
+  float(*coords)[2] = bm_face_array_calc_unique_uv_coords(
+      faces, faces_len, cd_loop_uv_offset, &coords_len);
+
+  float angle = BLI_convexhull_aabb_fit_points_2d(coords, coords_len);
+
+  if (align_to_axis != -1) {
+    if (angle != 0.0f) {
+      float matrix[2][2];
+      angle_to_mat2(matrix, angle);
+      for (int i = 0; i < coords_len; i++) {
+        mul_m2_v2(matrix, coords[i]);
+      }
+    }
+
+    float bounds_min[2], bounds_max[2];
+    INIT_MINMAX2(bounds_min, bounds_max);
+    for (int i = 0; i < coords_len; i++) {
+      minmax_v2v2_v2(bounds_min, bounds_max, coords[i]);
+    }
+
+    float size[2];
+    sub_v2_v2v2(size, bounds_max, bounds_min);
+    if (align_to_axis ? (size[1] < size[0]) : (size[0] < size[1])) {
+      angle += DEG2RAD(90.0);
+    }
+  }
+
+  MEM_freeN(coords);
+
+  if (angle != 0.0f) {
+    float matrix[2][2];
+    angle_to_mat2(matrix, angle);
+    for (int i = 0; i < faces_len; i++) {
+      BM_face_uv_transform(faces[i], matrix, cd_loop_uv_offset);
+    }
+  }
+}
+
+static void bm_face_array_uv_scale_y(BMFace **faces,
+                                     int faces_len,
+                                     const float scale_y,
+                                     const uint cd_loop_uv_offset)
+{
+  for (int i = 0; i < faces_len; i++) {
+    BMFace *f = faces[i];
+    bm_face_uv_scale_y(f, scale_y, cd_loop_uv_offset);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Calculate UV Islands
+ *
+ * \note Currently this is a private API/type, it could be made public.
+ * \{ */
+
+struct FaceIsland {
+  struct FaceIsland *next, *prev;
+  BMFace **faces;
+  int faces_len;
+  rctf bounds_rect;
+  /**
+   * \note While this is duplicate information,
+   * it allows islands from multiple meshes to be stored in the same list.
+   */
+  uint cd_loop_uv_offset;
+  float aspect_y;
+};
+
+struct SharedUVLoopData {
+  uint cd_loop_uv_offset;
+};
+
+static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, void *user_data)
+{
+  const struct SharedUVLoopData *data = user_data;
+  return BM_loop_uv_share_edge_check((BMLoop *)l_a, (BMLoop *)l_b, data->cd_loop_uv_offset);
+}
+
+/**
+ * Calculate islands a

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list