Blender V5.0
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
8
9#include "BLI_math_base.h"
11#include "BLI_task.hh"
12
13#include "BKE_attribute.hh"
14#include "BKE_mesh.hh"
15
16#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
17
18using namespace blender;
19
20enum {
24};
25
26static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
27{
28 if (uv_a[0] == uv_b[0] && uv_a[1] == uv_b[1]) {
29 return CMP_EQUAL;
30 }
31 /* NOTE(@ideasman42): that the ULP value is the primary value used to compare relative
32 * values as the absolute value doesn't account for float precision at difference scales.
33 * - For subdivision-surface ULP of 3 is sufficient,
34 * although this value is extremely small.
35 * - For bevel the ULP of 12 is sufficient to merge UVs that appear to be connected
36 * with bevel on Suzanne beveled 15% with 6 segments.
37 *
38 * These values could be tweaked but should be kept on the small side to prevent
39 * unintentional joining of intentionally disconnected UVs.
40 *
41 * Before v2.91 the threshold was either (`1e-4` or `0.05 / image_size` for selection picking).
42 * So picking used a threshold of `1e-4` for a 500x500 image and `1e-5` for a 5000x5000 image.
43 * Given this value worked reasonably well for a long time, the absolute difference should
44 * never exceed `1e-4` (#STD_UV_CONNECT_LIMIT which is still used in a few areas). */
45 const float diff_abs = 1e-12f;
46 const int diff_ulp = 12;
47
48 if (compare_ff_relative(uv_a[0], uv_b[0], diff_abs, diff_ulp) &&
49 compare_ff_relative(uv_a[1], uv_b[1], diff_abs, diff_ulp))
50 {
51 return CMP_CLOSE;
52 }
53 return CMP_APART;
54}
55
56static void merge_uvs_for_vertex(const Span<int> loops_for_vert, Span<float2 *> uv_map_layers)
57{
58 if (loops_for_vert.size() <= 1) {
59 return;
60 }
61 /* Manipulate a copy of the loop indices, de-duplicating UVs per layer. */
62 Vector<int, 32> loops_merge;
63 loops_merge.reserve(loops_for_vert.size());
64 for (float2 *uv_map : uv_map_layers) {
65 BLI_assert(loops_merge.is_empty());
66 loops_merge.extend_unchecked(loops_for_vert);
67 while (loops_merge.size() > 1) {
68 uint i_last = uint(loops_merge.size()) - 1;
69 const float *uv_src = uv_map[loops_merge[0]];
70 for (uint i = 1; i <= i_last;) {
71 float *uv_dst = uv_map[loops_merge[i]];
72 switch (compare_v2_classify(uv_src, uv_dst)) {
73 case CMP_CLOSE: {
74 uv_dst[0] = uv_src[0];
75 uv_dst[1] = uv_src[1];
77 }
78 case CMP_EQUAL: {
79 loops_merge[i] = loops_merge[i_last--];
80 break;
81 }
82 case CMP_APART: {
83 /* Doesn't match, check the next UV. */
84 i++;
85 break;
86 }
87 default: {
89 }
90 }
91 }
92 /* Finished de-duplicating with the first index, throw it away. */
93 loops_merge[0] = loops_merge[i_last];
94 loops_merge.resize(i_last);
95 }
96 loops_merge.clear();
97 }
98}
99
101{
102 using namespace blender::bke;
103 if (mesh->corners_num == 0) {
104 return;
105 }
106 MutableAttributeAccessor attributes = mesh->attributes_for_write();
108 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
109 if (iter.data_type != AttrType::Float2) {
110 return;
111 }
112 if (iter.domain != AttrDomain::Corner) {
113 return;
114 }
115 uv_map_attrs.append(attributes.lookup_for_write_span<float2>(iter.name));
116 });
117
118 if (uv_map_attrs.is_empty()) {
119 return;
120 }
121
122 const GroupedSpan<int> vert_to_corner = mesh->vert_to_corner_map();
123
124 Vector<float2 *> uv_map_layers;
125 for (SpanAttributeWriter<float2> &attr : uv_map_attrs) {
126 uv_map_layers.append(attr.span.data());
127 }
128
129 threading::parallel_for(IndexRange(mesh->verts_num), 1024, [&](IndexRange range) {
130 for (const int64_t v_index : range) {
131 merge_uvs_for_vertex(vert_to_corner[v_index], uv_map_layers);
132 }
133 });
134
135 for (SpanAttributeWriter<float2> &attr : uv_map_attrs) {
136 attr.finish();
137 }
138}
#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)
unsigned int uint
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
void append(const T &value)
bool is_empty() const
void extend_unchecked(Span< T > array)
void reserve(const int64_t min_capacity)
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
static void merge_uvs_for_vertex(const Span< int > loops_for_vert, Span< float2 * > uv_map_layers)
void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *mesh)
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:93
i
Definition text_draw.cc:230