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