Blender V5.0
mesh_fair.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
10
11#include "BLI_map.hh"
12#include "BLI_math_geom.h"
13#include "BLI_math_vector.h"
14#include "BLI_vector.hh"
15
16#include "BKE_mesh.hh"
17#include "BKE_mesh_fair.hh"
18
19#include "eigen_capi.h"
20
21using blender::Array;
22using blender::float3;
23using blender::Map;
25using blender::Span;
26using blender::Vector;
27using std::array;
28
30 public:
31 virtual float weight_at_index(const int index) const = 0;
32 virtual ~VertexWeight() = default;
33};
34
36 public:
37 virtual float weight_at_index(const int index) const = 0;
38 virtual ~LoopWeight() = default;
39};
40
42 public:
43 /* Get coordinates of vertices which are adjacent to the loop with specified index. */
44 virtual void adjacents_coords_from_loop(const int loop,
45 float r_adj_next[3],
46 float r_adj_prev[3]) = 0;
47
48 /* Get the other vertex index for a loop. */
49 virtual int other_vertex_index_from_loop(const int loop, const int v) = 0;
50
52 {
53 return totvert_;
54 }
55
57 {
58 return totvert_;
59 }
60
62 {
63 return vlmap_[v];
64 }
65
66 float *vertex_deformation_co_get(const int v)
67 {
68 return co_[v];
69 }
70
71 virtual ~FairingContext() = default;
72
73 void fair_verts(const bool affected_verts[],
74 const eMeshFairingDepth depth,
75 const VertexWeight &vertex_weight,
76 const LoopWeight &loop_weight)
77 {
78 fair_verts_ex(affected_verts, int(depth), vertex_weight, loop_weight);
79 }
80
81 protected:
83
86
88
89 private:
90 void fair_setup_fairing(const int v,
91 const int i,
92 LinearSolver *solver,
93 float multiplier,
94 const int depth,
95 Map<int, int> &vert_col_map,
96 const VertexWeight &vertex_weight,
97 const LoopWeight &loop_weight)
98 {
99 if (depth == 0) {
100 if (vert_col_map.contains(v)) {
101 const int j = vert_col_map.lookup(v);
102 EIG_linear_solver_matrix_add(solver, i, j, -multiplier);
103 return;
104 }
105 for (int j = 0; j < 3; j++) {
106 EIG_linear_solver_right_hand_side_add(solver, j, i, multiplier * co_[v][j]);
107 }
108 return;
109 }
110
111 float w_ij_sum = 0;
112 const float w_i = vertex_weight.weight_at_index(v);
113 const Span<int> vlmap_elem = vlmap_[v];
114 for (const int l : vlmap_elem.index_range()) {
115 const int l_index = vlmap_elem[l];
116 const int other_vert = other_vertex_index_from_loop(l_index, v);
117 const float w_ij = loop_weight.weight_at_index(l_index);
118 w_ij_sum += w_ij;
119 fair_setup_fairing(other_vert,
120 i,
121 solver,
122 w_i * w_ij * multiplier,
123 depth - 1,
124 vert_col_map,
125 vertex_weight,
126 loop_weight);
127 }
128 fair_setup_fairing(v,
129 i,
130 solver,
131 -1 * w_i * w_ij_sum * multiplier,
132 depth - 1,
133 vert_col_map,
134 vertex_weight,
135 loop_weight);
136 }
137
138 void fair_verts_ex(const bool affected_verts[],
139 const int order,
140 const VertexWeight &vertex_weight,
141 const LoopWeight &loop_weight)
142 {
143 Map<int, int> vert_col_map;
144 int affected_verts_num = 0;
145 for (int i = 0; i < totvert_; i++) {
146 if (!affected_verts[i]) {
147 continue;
148 }
149 vert_col_map.add(i, affected_verts_num);
150 affected_verts_num++;
151 }
152
153 /* Early return, nothing to do. */
154 if (ELEM(affected_verts_num, 0, totvert_)) {
155 return;
156 }
157
158 /* Setup fairing matrices */
159 LinearSolver *solver = EIG_linear_solver_new(affected_verts_num, affected_verts_num, 3);
160 for (auto item : vert_col_map.items()) {
161 const int v = item.key;
162 const int col = item.value;
163 fair_setup_fairing(v, col, solver, 1.0f, order, vert_col_map, vertex_weight, loop_weight);
164 }
165
166 /* Solve linear system */
168
169 /* Copy the result back to the mesh */
170 for (auto item : vert_col_map.items()) {
171 const int v = item.key;
172 const int col = item.value;
173 for (int j = 0; j < 3; j++) {
174 co_[v][j] = EIG_linear_solver_variable_get(solver, j, col);
175 }
176 }
177
178 /* Free solver data */
180 }
181};
182
184 public:
186 {
187 totvert_ = mesh->verts_num;
188 totloop_ = mesh->corners_num;
189
190 MutableSpan<float3> positions = mesh->vert_positions_for_write();
191 edges_ = mesh->edges();
192 faces = mesh->faces();
193 corner_verts_ = mesh->corner_verts();
194 corner_edges_ = mesh->corner_edges();
195 vlmap_ = mesh->vert_to_corner_map();
196
197 /* Deformation coords. */
198 co_.resize(mesh->verts_num);
199 if (!deform_positions.is_empty()) {
200 for (int i = 0; i < mesh->verts_num; i++) {
201 co_[i] = deform_positions[i];
202 }
203 }
204 else {
205 for (int i = 0; i < mesh->verts_num; i++) {
206 co_[i] = positions[i];
207 }
208 }
209
210 loop_to_face_map_ = mesh->corner_to_face_map();
211 }
212
213 void adjacents_coords_from_loop(const int loop,
214 float r_adj_next[3],
215 float r_adj_prev[3]) override
216 {
217 using namespace blender;
218 const int vert = corner_verts_[loop];
219 const blender::IndexRange face = faces[loop_to_face_map_[loop]];
220 const int2 adjacent_verts = bke::mesh::face_find_adjacent_verts(face, corner_verts_, vert);
221 copy_v3_v3(r_adj_next, co_[adjacent_verts[0]]);
222 copy_v3_v3(r_adj_prev, co_[adjacent_verts[1]]);
223 }
224
225 int other_vertex_index_from_loop(const int loop, const int v) override
226 {
227 const blender::int2 &edge = edges_[corner_edges_[loop]];
229 }
230
231 protected:
238};
239
241 public:
243 {
244 const int totvert = fairing_context.vertex_count_get();
245 vertex_weights_.resize(totvert);
246 for (int i = 0; i < totvert; i++) {
247 const int tot_loop = fairing_context.vertex_loop_map_get(i).size();
248 if (tot_loop != 0) {
249 vertex_weights_[i] = 1.0f / tot_loop;
250 }
251 else {
252 vertex_weights_[i] = FLT_MAX;
253 }
254 }
255 }
256
257 float weight_at_index(const int index) const override
258 {
259 return vertex_weights_[index];
260 }
261
262 private:
263 Vector<float> vertex_weights_;
264};
265
267
268 public:
270 {
271
272 const int totvert = fairing_context.vertex_count_get();
273 vertex_weights_.resize(totvert);
274 for (int i = 0; i < totvert; i++) {
275
276 float area = 0.0f;
277 float a[3];
278 copy_v3_v3(a, fairing_context.vertex_deformation_co_get(i));
279 const float acute_threshold = M_PI_2;
280
281 const Span<int> vlmap_elem = fairing_context.vertex_loop_map_get(i);
282 for (const int l : vlmap_elem.index_range()) {
283 const int l_index = vlmap_elem[l];
284
285 float b[3], c[3], d[3];
286 fairing_context.adjacents_coords_from_loop(l_index, b, c);
287
288 if (angle_v3v3v3(c, fairing_context.vertex_deformation_co_get(i), b) < acute_threshold) {
289 calc_circumcenter(d, a, b, c);
290 }
291 else {
292 add_v3_v3v3(d, b, c);
293 mul_v3_fl(d, 0.5f);
294 }
295
296 float t[3];
297 add_v3_v3v3(t, a, b);
298 mul_v3_fl(t, 0.5f);
299 area += area_tri_v3(a, t, d);
300
301 add_v3_v3v3(t, a, c);
302 mul_v3_fl(t, 0.5f);
303 area += area_tri_v3(a, d, t);
304 }
305
306 vertex_weights_[i] = area != 0.0f ? 1.0f / area : 1e12;
307 }
308 }
309
310 float weight_at_index(const int index) const override
311 {
312 return vertex_weights_[index];
313 }
314
315 private:
316 Vector<float> vertex_weights_;
317
318 void calc_circumcenter(float r[3], const float a[3], const float b[3], const float c[3])
319 {
320 float ab[3];
321 sub_v3_v3v3(ab, b, a);
322
323 float ac[3];
324 sub_v3_v3v3(ac, c, a);
325
326 float ab_cross_ac[3];
327 cross_v3_v3v3(ab_cross_ac, ab, ac);
328
329 if (len_squared_v3(ab_cross_ac) > 0.0f) {
330 float d[3];
331 cross_v3_v3v3(d, ab_cross_ac, ab);
333
334 float t[3];
335 cross_v3_v3v3(t, ac, ab_cross_ac);
337
338 add_v3_v3(d, t);
339
340 mul_v3_fl(d, 1.0f / (2.0f * len_squared_v3(ab_cross_ac)));
341
342 add_v3_v3v3(r, a, d);
343 return;
344 }
345 copy_v3_v3(r, a);
346 }
347};
348
350 public:
351 float weight_at_index(const int /*index*/) const override
352 {
353 return 1.0f;
354 }
355};
356
357static void prefair_and_fair_verts(FairingContext &fairing_context,
358 const bool affected_verts[],
359 const eMeshFairingDepth depth)
360{
361 /* Pre-fair. */
362 UniformVertexWeight uniform_vertex_weights(fairing_context);
363 UniformLoopWeight uniform_loop_weights;
364 fairing_context.fair_verts(affected_verts, depth, uniform_vertex_weights, uniform_loop_weights);
365
366 /* Fair. */
367 VoronoiVertexWeight voronoi_vertex_weights(fairing_context);
368 /* TODO: Implement cotangent loop weights. */
369 fairing_context.fair_verts(affected_verts, depth, voronoi_vertex_weights, uniform_loop_weights);
370}
371
373 blender::MutableSpan<float3> deform_vert_positions,
374 const bool affected_verts[],
375 const eMeshFairingDepth depth)
376{
377 MutableSpan<float3> deform_positions_span;
378 if (!deform_vert_positions.is_empty()) {
379 deform_positions_span = deform_vert_positions;
380 }
381 MeshFairingContext fairing_context(mesh, deform_positions_span);
382 prefair_and_fair_verts(fairing_context, affected_verts, depth);
383}
eMeshFairingDepth
#define M_PI_2
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:100
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
#define ELEM(...)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
Span< int > vertex_loop_map_get(const int v)
Definition mesh_fair.cc:61
blender::GroupedSpan< int > vlmap_
Definition mesh_fair.cc:87
int loop_count_get()
Definition mesh_fair.cc:56
int vertex_count_get()
Definition mesh_fair.cc:51
Vector< float * > co_
Definition mesh_fair.cc:82
virtual ~FairingContext()=default
void fair_verts(const bool affected_verts[], const eMeshFairingDepth depth, const VertexWeight &vertex_weight, const LoopWeight &loop_weight)
Definition mesh_fair.cc:73
virtual void adjacents_coords_from_loop(const int loop, float r_adj_next[3], float r_adj_prev[3])=0
float * vertex_deformation_co_get(const int v)
Definition mesh_fair.cc:66
virtual int other_vertex_index_from_loop(const int loop, const int v)=0
virtual float weight_at_index(const int index) const =0
virtual ~LoopWeight()=default
void adjacents_coords_from_loop(const int loop, float r_adj_next[3], float r_adj_prev[3]) override
Definition mesh_fair.cc:213
Span< int > corner_edges_
Definition mesh_fair.cc:234
blender::OffsetIndices< int > faces
Definition mesh_fair.cc:235
int other_vertex_index_from_loop(const int loop, const int v) override
Definition mesh_fair.cc:225
Span< blender::int2 > edges_
Definition mesh_fair.cc:236
MeshFairingContext(Mesh *mesh, MutableSpan< float3 > deform_positions)
Definition mesh_fair.cc:185
Span< int > loop_to_face_map_
Definition mesh_fair.cc:237
Span< int > corner_verts_
Definition mesh_fair.cc:233
float weight_at_index(const int) const override
Definition mesh_fair.cc:351
float weight_at_index(const int index) const override
Definition mesh_fair.cc:257
UniformVertexWeight(FairingContext &fairing_context)
Definition mesh_fair.cc:242
virtual float weight_at_index(const int index) const =0
virtual ~VertexWeight()=default
float weight_at_index(const int index) const override
Definition mesh_fair.cc:310
VoronoiVertexWeight(FairingContext &fairing_context)
Definition mesh_fair.cc:269
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
bool contains(const Key &key) const
Definition BLI_map.hh:353
ItemIterator items() const &
Definition BLI_map.hh:902
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
uint col
LinearSolver * EIG_linear_solver_new(int num_rows, int num_columns, int num_right_hand_sides)
void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_delete(LinearSolver *solver)
double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index)
void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value)
bool EIG_linear_solver_solve(LinearSolver *solver)
void BKE_mesh_prefair_and_fair_verts(Mesh *mesh, blender::MutableSpan< float3 > deform_vert_positions, const bool affected_verts[], const eMeshFairingDepth depth)
Definition mesh_fair.cc:372
static void prefair_and_fair_verts(FairingContext &fairing_context, const bool affected_verts[], const eMeshFairingDepth depth)
Definition mesh_fair.cc:357
int edge_other_vert(const int2 edge, const int vert)
Definition BKE_mesh.hh:370
int2 face_find_adjacent_verts(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:338
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
#define FLT_MAX
Definition stdcycles.h:14
int corners_num
int verts_num
i
Definition text_draw.cc:230