Blender  V3.3
mesh_merge_customdata.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include "DNA_mesh_types.h"
10 #include "DNA_meshdata_types.h"
11 
12 #include "BLI_math.h"
13 #include "BLI_task.hh"
14 #include "BLI_utildefines.h"
15 
16 #include "BKE_customdata.h"
17 #include "BKE_mesh.h"
18 #include "BKE_mesh_mapping.h"
19 #include "BLI_memarena.h"
20 
21 #include "BLI_strict_flags.h"
22 
23 using namespace blender;
24 
25 enum {
26  CMP_CLOSE = 0,
27  CMP_EQUAL = 1,
28  CMP_APART = 2,
29 };
30 
31 static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
32 {
33  if (uv_a[0] == uv_b[0] && uv_a[1] == uv_b[1]) {
34  return CMP_EQUAL;
35  }
36  /* NOTE(@campbellbarton): that the ULP value is the primary value used to compare relative
37  * values as the absolute value doesn't account for float precision at difference scales.
38  * - For subdivision-surface ULP of 3 is sufficient,
39  * although this value is extremely small.
40  * - For bevel the ULP of 12 is sufficient to merge UV's that appear to be connected
41  * with bevel on Suzanne beveled 15% with 6 segments.
42  *
43  * These values could be tweaked but should be kept on the small side to prevent
44  * unintentional joining of intentionally dis-connected UV's.
45  *
46  * Before v2.91 the threshold was either (`1e-4` or `0.05 / image_size` for selection picking).
47  * So picking used a threshold of `1e-4` for a 500x500 image and `1e-5` for a 5000x5000 image.
48  * Given this value worked reasonably well for a long time, the absolute difference should
49  * never exceed `1e-4` (#STD_UV_CONNECT_LIMIT which is still used in a few areas). */
50  const float diff_abs = 1e-12f;
51  const int diff_ulp = 12;
52 
53  if (compare_ff_relative(uv_a[0], uv_b[0], diff_abs, diff_ulp) &&
54  compare_ff_relative(uv_a[1], uv_b[1], diff_abs, diff_ulp)) {
55  return CMP_CLOSE;
56  }
57  return CMP_APART;
58 }
59 
60 static void merge_uvs_for_vertex(const Span<int> loops_for_vert, Span<MLoopUV *> mloopuv_layers)
61 {
62  if (loops_for_vert.size() <= 1) {
63  return;
64  }
65  /* Manipulate a copy of the loop indices, de-duplicating UV's per layer. */
66  Vector<int, 32> loops_merge;
67  loops_merge.reserve(loops_for_vert.size());
68  for (MLoopUV *mloopuv : mloopuv_layers) {
69  BLI_assert(loops_merge.is_empty());
70  loops_merge.extend_unchecked(loops_for_vert);
71  while (loops_merge.size() > 1) {
72  uint i_last = (uint)loops_merge.size() - 1;
73  const float *uv_src = mloopuv[loops_merge[0]].uv;
74  for (uint i = 1; i <= i_last;) {
75  float *uv_dst = mloopuv[loops_merge[i]].uv;
76  switch (compare_v2_classify(uv_src, uv_dst)) {
77  case CMP_CLOSE: {
78  uv_dst[0] = uv_src[0];
79  uv_dst[1] = uv_src[1];
81  }
82  case CMP_EQUAL: {
83  loops_merge[i] = loops_merge[i_last--];
84  break;
85  }
86  case CMP_APART: {
87  /* Doesn't match, check the next UV. */
88  i++;
89  break;
90  }
91  default: {
93  }
94  }
95  }
96  /* Finished de-duplicating with the first index, throw it away. */
97  loops_merge[0] = loops_merge[i_last];
98  loops_merge.resize(i_last);
99  }
100  loops_merge.clear();
101  }
102 }
103 
105 {
106  if (me->totloop == 0) {
107  return;
108  }
109  const int mloopuv_layers_num = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
110  if (mloopuv_layers_num == 0) {
111  return;
112  }
113 
114  int *vert_map_mem;
115  struct MeshElemMap *vert_to_loop;
117  &vert_to_loop, &vert_map_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
118 
119  Vector<MLoopUV *> mloopuv_layers;
120  mloopuv_layers.reserve(mloopuv_layers_num);
121  for (int a = 0; a < mloopuv_layers_num; a++) {
122  MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a));
123  mloopuv_layers.append_unchecked(mloopuv);
124  }
125 
126  Span<MLoopUV *> mloopuv_layers_as_span = mloopuv_layers.as_span();
127  threading::parallel_for(IndexRange(me->totvert), 1024, [&](IndexRange range) {
128  for (const int64_t v_index : range) {
129  MeshElemMap &loops_for_vert = vert_to_loop[v_index];
130  Span<int> loops_for_vert_span(loops_for_vert.indices, loops_for_vert.count);
131  merge_uvs_for_vertex(loops_for_vert_span, mloopuv_layers_as_span);
132  }
133  });
134 
135  MEM_freeN(vert_to_loop);
136  MEM_freeN(vert_map_mem);
137 }
CustomData interface, see also DNA_customdata_types.h.
int CustomData_number_of_layers(const struct CustomData *data, int type)
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem, const struct MPoly *mpoly, const struct MLoop *mloop, int totvert, int totpoly, int totloop)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ATTR_FALLTHROUGH
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:67
@ CD_MLOOPUV
Read Guarded memory(de)allocation.
constexpr int64_t size() const
Definition: BLI_span.hh:240
int64_t size() const
Definition: BLI_vector.hh:694
Span< T > as_span() const
Definition: BLI_vector.hh:325
bool is_empty() const
Definition: BLI_vector.hh:706
void resize(const int64_t new_size)
Definition: BLI_vector.hh:353
void extend_unchecked(Span< T > array)
Definition: BLI_vector.hh:556
void append_unchecked(const T &value)
Definition: BLI_vector.hh:484
void reserve(const int64_t min_capacity)
Definition: BLI_vector.hh:340
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
static void merge_uvs_for_vertex(const Span< int > loops_for_vert, Span< MLoopUV * > mloopuv_layers)
static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *me)
static unsigned a[3]
Definition: RandGen.cpp:78
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata