Blender V5.0
deform_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_deform.hh"
6
8
9#include "testing/testing.h"
10
11namespace blender::bke::tests {
12
13TEST(vertex_weights_normalize, EmptyWeights)
14{
15 /* Just making sure we don't crash on a vertex with no weights. */
16
17 /* Some compilers don't like zero-length arrays, so we just do nullptr here as
18 * a stand-in. */
19 MDeformWeight *weights = nullptr;
20
21 MDeformVert vert = {weights, 0, 0};
22
23 BKE_defvert_normalize_ex(vert, {}, {}, {});
24}
25
26TEST(vertex_weights_normalize, SingleWeight)
27{
28 MDeformWeight weights[1];
29 weights[0].def_nr = 0;
30 MDeformVert vert = {weights, 1, 0};
31
32 /* Excluded from normalized set: shouldn't be touched. */
33 weights[0].weight = 0.5;
34 BKE_defvert_normalize_ex(vert, {false}, {false}, {false});
35 EXPECT_FLOAT_EQ(0.5, weights[0].weight);
36
37 /* Locked: shouldn't be touched. */
38 weights[0].weight = 0.5;
39 BKE_defvert_normalize_ex(vert, {true}, {true}, {false});
40 EXPECT_FLOAT_EQ(0.5, weights[0].weight);
41
42 /* Unlocked: should get normalized to 1.0. */
43 weights[0].weight = 0.5;
44 BKE_defvert_normalize_ex(vert, {true}, {false}, {false});
45 EXPECT_FLOAT_EQ(1.0, weights[0].weight);
46
47 /* Unlocked and soft-locked: should get normalized to 1.0. */
48 weights[0].weight = 0.5;
49 BKE_defvert_normalize_ex(vert, {true}, {false}, {true});
50 EXPECT_FLOAT_EQ(1.0, weights[0].weight);
51
52 /* Locked and soft-locked: shouldn't be touched (locked takes precedent). */
53 weights[0].weight = 0.5;
54 BKE_defvert_normalize_ex(vert, {true}, {true}, {true});
55 EXPECT_FLOAT_EQ(0.5, weights[0].weight);
56
57 /* An empty "subset" flag list should be equivalent to everything being included. */
58 weights[0].weight = 0.5;
59 BKE_defvert_normalize_ex(vert, {}, {false}, {false});
60 EXPECT_FLOAT_EQ(1.0, weights[0].weight);
61
62 /* An empty "locked" flag list should be equivalent to everything being unlocked. */
63 weights[0].weight = 0.5;
64 BKE_defvert_normalize_ex(vert, {true}, {}, {false});
65 EXPECT_FLOAT_EQ(1.0, weights[0].weight);
66
67 /* Zero weight: single-group vertices are special cased for some reason to be
68 * set to 1.0. */
69 weights[0].weight = 0.0;
70 BKE_defvert_normalize_ex(vert, {}, {}, {});
71 EXPECT_FLOAT_EQ(1.0, weights[0].weight);
72
73 /* Zero weight locked: shouldn't be touched. */
74 weights[0].weight = 0.0;
75 BKE_defvert_normalize_ex(vert, {}, {true}, {});
76 EXPECT_FLOAT_EQ(0.0, weights[0].weight);
77}
78
79TEST(vertex_weights_normalize, TwoWeights)
80{
81 MDeformWeight weights[2];
82 weights[0].def_nr = 0;
83 weights[1].def_nr = 1;
84 MDeformVert vert = {weights, 2, 0};
85
86 /* Both excluded from normalized set: shouldn't be touched. */
87 weights[0].weight = 0.25;
88 weights[1].weight = 0.25;
89 BKE_defvert_normalize_ex(vert, {false, false}, {false, false}, {false, false});
90 EXPECT_FLOAT_EQ(0.25, weights[0].weight);
91 EXPECT_FLOAT_EQ(0.25, weights[1].weight);
92
93 /* One included: included one should be set to 1.0. */
94 weights[0].weight = 0.25;
95 weights[1].weight = 0.25;
96 BKE_defvert_normalize_ex(vert, {false, true}, {false, false}, {false, false});
97 EXPECT_FLOAT_EQ(0.25, weights[0].weight);
98 EXPECT_FLOAT_EQ(1.0, weights[1].weight);
99
100 /* Both included: should be normalized together. */
101 weights[0].weight = 0.25;
102 weights[1].weight = 0.25;
103 BKE_defvert_normalize_ex(vert, {true, true}, {false, false}, {false, false});
104 EXPECT_FLOAT_EQ(0.5, weights[0].weight);
105 EXPECT_FLOAT_EQ(0.5, weights[1].weight);
106
107 /* All flag arrays being empty should mean: included, unlocked, and not "just
108 * set". So this should behave as a simple normalization across both groups. */
109 weights[0].weight = 0.25;
110 weights[1].weight = 0.25;
111 BKE_defvert_normalize_ex(vert, {}, {}, {});
112 EXPECT_FLOAT_EQ(0.5, weights[0].weight);
113 EXPECT_FLOAT_EQ(0.5, weights[1].weight);
114
115 /* Both included but locked: shouldn't be touched. */
116 weights[0].weight = 0.25;
117 weights[1].weight = 0.25;
118 BKE_defvert_normalize_ex(vert, {}, {true, true}, {false, false});
119 EXPECT_FLOAT_EQ(0.25, weights[0].weight);
120 EXPECT_FLOAT_EQ(0.25, weights[1].weight);
121
122 /* Only one locked: locked shouldn't be touched, unlocked should pick up the
123 * slack for normalization. */
124 weights[0].weight = 0.25;
125 weights[1].weight = 0.25;
126 BKE_defvert_normalize_ex(vert, {}, {true, false}, {false, false});
127 EXPECT_FLOAT_EQ(0.25, weights[0].weight);
128 EXPECT_FLOAT_EQ(0.75, weights[1].weight);
129
130 /* Only one marked as soft-locked: soft-locked shouldn't be touched, the other
131 * should pick up the slack for normalization. */
132 weights[0].weight = 0.25;
133 weights[1].weight = 0.25;
134 BKE_defvert_normalize_ex(vert, {}, {false, false}, {true, false});
135 EXPECT_FLOAT_EQ(0.25, weights[0].weight);
136 EXPECT_FLOAT_EQ(0.75, weights[1].weight);
137
138 /* One locked, the other marked as soft-locked: soft-locked should pick up the
139 * slack for normalization. */
140 weights[0].weight = 0.25;
141 weights[1].weight = 0.25;
142 BKE_defvert_normalize_ex(vert, {}, {true, false}, {false, true});
143 EXPECT_FLOAT_EQ(0.25, weights[0].weight);
144 EXPECT_FLOAT_EQ(0.75, weights[1].weight);
145
146 /* Zero weight: shouldn't be touched. */
147 weights[0].weight = 0.0;
148 weights[1].weight = 0.0;
149 BKE_defvert_normalize_ex(vert, {}, {false, false}, {false, false});
150 EXPECT_FLOAT_EQ(0.0, weights[0].weight);
151 EXPECT_FLOAT_EQ(0.0, weights[1].weight);
152
153 /* Zero weight with one group soft-locked: soft-locked should pick up the slack. */
154 weights[0].weight = 0.0;
155 weights[1].weight = 0.0;
156 BKE_defvert_normalize_ex(vert, {}, {false, false}, {false, true});
157 EXPECT_FLOAT_EQ(0.0, weights[0].weight);
158 EXPECT_FLOAT_EQ(1.0, weights[1].weight);
159
160 /* Zero weight with both groups soft-locked: both should pick up the slack equally. */
161 weights[0].weight = 0.0;
162 weights[1].weight = 0.0;
163 BKE_defvert_normalize_ex(vert, {}, {false, false}, {true, true});
164 EXPECT_FLOAT_EQ(0.5, weights[0].weight);
165 EXPECT_FLOAT_EQ(0.5, weights[1].weight);
166}
167
168TEST(vertex_weights_normalize, FourWeights)
169{
170 /* Note the out-of-order `def_nr`, which is part of this test. Further below,
171 * we write the weights ordered to line up with the boolean arrays to make
172 * things easier to follow. */
173 MDeformWeight weights[4];
174 weights[0].def_nr = 3;
175 weights[1].def_nr = 0;
176 weights[2].def_nr = 1;
177 weights[3].def_nr = 2;
178 MDeformVert vert = {weights, 4, 0};
179
180 /* One locked, one soft-locked: the remaining two should pick up the slack. */
181 weights[1].weight = 0.125;
182 weights[2].weight = 0.125;
183 weights[3].weight = 0.125;
184 weights[0].weight = 0.0625;
185 BKE_defvert_normalize_ex(vert, {}, {true, false, false, false}, {false, false, true, false});
186 EXPECT_FLOAT_EQ(0.125, weights[1].weight);
187 EXPECT_FLOAT_EQ(0.75 * 2.0 / 3.0, weights[2].weight);
188 EXPECT_FLOAT_EQ(0.125, weights[3].weight);
189 EXPECT_FLOAT_EQ(0.75 / 3.0, weights[0].weight);
190
191 /* One locked, two soft-locked: the remaining one should pick up the slack. */
192 weights[1].weight = 0.125;
193 weights[2].weight = 0.125;
194 weights[3].weight = 0.125;
195 weights[0].weight = 0.125;
196 BKE_defvert_normalize_ex(vert, {}, {true, false, false, false}, {false, true, true, false});
197 EXPECT_FLOAT_EQ(0.125, weights[1].weight);
198 EXPECT_FLOAT_EQ(0.125, weights[2].weight);
199 EXPECT_FLOAT_EQ(0.125, weights[3].weight);
200 EXPECT_FLOAT_EQ(0.625, weights[0].weight);
201
202 /* One locked, one soft-locked, and the rest zero-weight: the soft-locked one
203 * should pick up the slack. */
204 weights[1].weight = 0.125;
205 weights[2].weight = 0.0;
206 weights[3].weight = 0.125;
207 weights[0].weight = 0.0;
208 BKE_defvert_normalize_ex(vert, {}, {true, false, false, false}, {false, false, true, false});
209 EXPECT_FLOAT_EQ(0.125, weights[1].weight);
210 EXPECT_FLOAT_EQ(0.0, weights[2].weight);
211 EXPECT_FLOAT_EQ(0.875, weights[3].weight);
212 EXPECT_FLOAT_EQ(0.0, weights[0].weight);
213
214 /* One locked, two soft-locked, and the last zero-weight: the soft-locked ones
215 * should pick up the slack. */
216 weights[1].weight = 0.125;
217 weights[2].weight = 0.125;
218 weights[3].weight = 0.25;
219 weights[0].weight = 0.0;
220 BKE_defvert_normalize_ex(vert, {}, {true, false, false, false}, {false, true, true, false});
221 EXPECT_FLOAT_EQ(0.125, weights[1].weight);
222 EXPECT_FLOAT_EQ(0.875 / 3.0, weights[2].weight);
223 EXPECT_FLOAT_EQ(0.875 * 2.0 / 3.0, weights[3].weight);
224 EXPECT_FLOAT_EQ(0.0f, weights[0].weight);
225}
226
227} // namespace blender::bke::tests
support for deformation groups and hooks.
void BKE_defvert_normalize_ex(MDeformVert &dvert, blender::Span< bool > vgroup_subset, blender::Span< bool > lock_flags, blender::Span< bool > soft_lock_flags)
Definition deform.cc:249
TEST(action_groups, ReconstructGroupsWithReordering)
unsigned int def_nr