Blender V4.3
mesh_merge_customdata.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
12#include "BLI_task.hh"
13#include "BLI_utildefines.h"
14
15#include "BKE_customdata.hh"
16#include "BKE_mesh.hh"
17
18#include "BLI_strict_flags.h" /* Keep last. */
19
20using namespace blender;
21
22enum {
26};
27
28static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
29{
30 if (uv_a[0] == uv_b[0] && uv_a[1] == uv_b[1]) {
31 return CMP_EQUAL;
32 }
33 /* NOTE(@ideasman42): that the ULP value is the primary value used to compare relative
34 * values as the absolute value doesn't account for float precision at difference scales.
35 * - For subdivision-surface ULP of 3 is sufficient,
36 * although this value is extremely small.
37 * - For bevel the ULP of 12 is sufficient to merge UVs that appear to be connected
38 * with bevel on Suzanne beveled 15% with 6 segments.
39 *
40 * These values could be tweaked but should be kept on the small side to prevent
41 * unintentional joining of intentionally disconnected UVs.
42 *
43 * Before v2.91 the threshold was either (`1e-4` or `0.05 / image_size` for selection picking).
44 * So picking used a threshold of `1e-4` for a 500x500 image and `1e-5` for a 5000x5000 image.
45 * Given this value worked reasonably well for a long time, the absolute difference should
46 * never exceed `1e-4` (#STD_UV_CONNECT_LIMIT which is still used in a few areas). */
47 const float diff_abs = 1e-12f;
48 const int diff_ulp = 12;
49
50 if (compare_ff_relative(uv_a[0], uv_b[0], diff_abs, diff_ulp) &&
51 compare_ff_relative(uv_a[1], uv_b[1], diff_abs, diff_ulp))
52 {
53 return CMP_CLOSE;
54 }
55 return CMP_APART;
56}
57
58static void merge_uvs_for_vertex(const Span<int> loops_for_vert, Span<float2 *> mloopuv_layers)
59{
60 if (loops_for_vert.size() <= 1) {
61 return;
62 }
63 /* Manipulate a copy of the loop indices, de-duplicating UVs per layer. */
64 Vector<int, 32> loops_merge;
65 loops_merge.reserve(loops_for_vert.size());
66 for (float2 *mloopuv : mloopuv_layers) {
67 BLI_assert(loops_merge.is_empty());
68 loops_merge.extend_unchecked(loops_for_vert);
69 while (loops_merge.size() > 1) {
70 uint i_last = uint(loops_merge.size()) - 1;
71 const float *uv_src = mloopuv[loops_merge[0]];
72 for (uint i = 1; i <= i_last;) {
73 float *uv_dst = mloopuv[loops_merge[i]];
74 switch (compare_v2_classify(uv_src, uv_dst)) {
75 case CMP_CLOSE: {
76 uv_dst[0] = uv_src[0];
77 uv_dst[1] = uv_src[1];
79 }
80 case CMP_EQUAL: {
81 loops_merge[i] = loops_merge[i_last--];
82 break;
83 }
84 case CMP_APART: {
85 /* Doesn't match, check the next UV. */
86 i++;
87 break;
88 }
89 default: {
91 }
92 }
93 }
94 /* Finished de-duplicating with the first index, throw it away. */
95 loops_merge[0] = loops_merge[i_last];
96 loops_merge.resize(i_last);
97 }
98 loops_merge.clear();
99 }
100}
101
103{
104 if (mesh->corners_num == 0) {
105 return;
106 }
107 const int mloopuv_layers_num = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
108 if (mloopuv_layers_num == 0) {
109 return;
110 }
111
112 const GroupedSpan<int> vert_to_corner = mesh->vert_to_corner_map();
113
114 Vector<float2 *> mloopuv_layers;
115 mloopuv_layers.reserve(mloopuv_layers_num);
116 for (int a = 0; a < mloopuv_layers_num; a++) {
117 float2 *mloopuv = static_cast<float2 *>(CustomData_get_layer_n_for_write(
118 &mesh->corner_data, CD_PROP_FLOAT2, a, mesh->corners_num));
119 mloopuv_layers.append_unchecked(mloopuv);
120 }
121
122 Span<float2 *> mloopuv_layers_as_span = mloopuv_layers.as_span();
123
124 threading::parallel_for(IndexRange(mesh->verts_num), 1024, [&](IndexRange range) {
125 for (const int64_t v_index : range) {
126 merge_uvs_for_vertex(vert_to_corner[v_index], mloopuv_layers_as_span);
127 }
128 });
129}
CustomData interface, see also DNA_customdata_types.h.
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
void * CustomData_get_layer_n_for_write(CustomData *data, eCustomDataType type, int n, int totelem)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
unsigned int uint
@ CD_PROP_FLOAT2
Read Guarded memory(de)allocation.
constexpr int64_t size() const
Definition BLI_span.hh:253
int64_t size() const
bool is_empty() const
void extend_unchecked(Span< T > array)
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
Span< T > as_span() const
static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *mesh)
static void merge_uvs_for_vertex(const Span< int > loops_for_vert, Span< float2 * > mloopuv_layers)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95