Blender V4.5
MOD_laplaciansmooth.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_geom.h"
10#include "BLI_utildefines.h"
11
12#include "BLT_translation.hh"
13
14#include "DNA_defaults.h"
15#include "DNA_mesh_types.h"
16#include "DNA_meshdata_types.h"
17#include "DNA_screen_types.h"
18
19#include "MEM_guardedalloc.h"
20
21#include "BKE_deform.hh"
22#include "BKE_modifier.hh"
23
24#include "UI_interface.hh"
25#include "UI_resources.hh"
26
27#include "RNA_prototypes.hh"
28
29#include "MOD_ui_common.hh"
30#include "MOD_util.hh"
31
32#include "eigen_capi.h"
33
34namespace {
35
36struct LaplacianSystem {
37 float *eweights = nullptr; /* Length weights per Edge */
38 float (*fweights)[3] = nullptr; /* Cotangent weights per face */
39 float *ring_areas = nullptr; /* Total area per ring. */
40 float *vlengths = nullptr; /* Total sum of lengths(edges) per vertex. */
41 float *vweights = nullptr; /* Total sum of weights per vertex. */
42 int verts_num = 0; /* Number of verts. */
43 short *ne_fa_num = nullptr; /* Number of neighbors faces around vertex. */
44 short *ne_ed_num = nullptr; /* Number of neighbors Edges around vertex. */
45 bool *zerola = nullptr; /* Is zero area or length. */
46
47 /* Pointers to data. */
48 float (*vertexCos)[3] = nullptr;
49 blender::Span<blender::int2> edges = {};
50 blender::OffsetIndices<int> faces = {};
51 blender::Span<int> corner_verts = {};
52 LinearSolver *context = nullptr;
53
54 /* Data. */
55 float min_area = 0.0f;
56 float vert_centroid[3] = {};
57};
58
59}; // namespace
60
62{
63 MEM_SAFE_FREE(sys->eweights);
65 MEM_SAFE_FREE(sys->ne_ed_num);
66 MEM_SAFE_FREE(sys->ne_fa_num);
67 MEM_SAFE_FREE(sys->ring_areas);
68 MEM_SAFE_FREE(sys->vlengths);
69 MEM_SAFE_FREE(sys->vweights);
70 MEM_SAFE_FREE(sys->zerola);
71
72 if (sys->context) {
74 }
75 sys->vertexCos = nullptr;
76 MEM_delete(sys);
77}
78
79static void memset_laplacian_system(LaplacianSystem *sys, int val)
80{
81 memset(sys->eweights, val, sizeof(float) * sys->edges.size());
82 memset(sys->fweights, val, sizeof(float[3]) * sys->corner_verts.size());
83 memset(sys->ne_ed_num, val, sizeof(short) * sys->verts_num);
84 memset(sys->ne_fa_num, val, sizeof(short) * sys->verts_num);
85 memset(sys->ring_areas, val, sizeof(float) * sys->verts_num);
86 memset(sys->vlengths, val, sizeof(float) * sys->verts_num);
87 memset(sys->vweights, val, sizeof(float) * sys->verts_num);
88 memset(sys->zerola, val, sizeof(bool) * sys->verts_num);
89}
90
91static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numLoops, int a_numVerts)
92{
93 LaplacianSystem *sys;
94 sys = MEM_new<LaplacianSystem>(__func__);
95 sys->verts_num = a_numVerts;
96
97 sys->eweights = MEM_calloc_arrayN<float>(a_numEdges, __func__);
98 sys->fweights = MEM_calloc_arrayN<float[3]>(a_numLoops, __func__);
99 sys->ne_ed_num = MEM_calloc_arrayN<short>(sys->verts_num, __func__);
100 sys->ne_fa_num = MEM_calloc_arrayN<short>(sys->verts_num, __func__);
101 sys->ring_areas = MEM_calloc_arrayN<float>(sys->verts_num, __func__);
102 sys->vlengths = MEM_calloc_arrayN<float>(sys->verts_num, __func__);
103 sys->vweights = MEM_calloc_arrayN<float>(sys->verts_num, __func__);
104 sys->zerola = MEM_calloc_arrayN<bool>(sys->verts_num, __func__);
105
106 return sys;
107}
108
109static float compute_volume(const float center[3],
110 float (*vertexCos)[3],
112 const blender::Span<int> corner_verts)
113{
114 float vol = 0.0f;
115
116 for (const int i : faces.index_range()) {
117 const blender::IndexRange face = faces[i];
118 int corner_first = face.start();
119 int corner_prev = corner_first + 1;
120 int corner_curr = corner_first + 2;
121 int corner_term = corner_first + face.size();
122
123 for (; corner_curr != corner_term; corner_prev = corner_curr, corner_curr++) {
124 vol += volume_tetrahedron_signed_v3(center,
125 vertexCos[corner_verts[corner_first]],
126 vertexCos[corner_verts[corner_prev]],
127 vertexCos[corner_verts[corner_curr]]);
128 }
129 }
130
131 return fabsf(vol);
132}
133
134static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag)
135{
136 float beta;
137 int i;
138
139 if (vend != 0.0f) {
140 beta = pow(vini / vend, 1.0f / 3.0f);
141 for (i = 0; i < sys->verts_num; i++) {
143 sys->vertexCos[i][0] = (sys->vertexCos[i][0] - sys->vert_centroid[0]) * beta +
144 sys->vert_centroid[0];
145 }
147 sys->vertexCos[i][1] = (sys->vertexCos[i][1] - sys->vert_centroid[1]) * beta +
148 sys->vert_centroid[1];
149 }
151 sys->vertexCos[i][2] = (sys->vertexCos[i][2] - sys->vert_centroid[2]) * beta +
152 sys->vert_centroid[2];
153 }
154 }
155 }
156}
157
159{
160 float *v1, *v2;
161 float w1, w2, w3;
162 float areaf;
163 int i;
164 uint idv1, idv2;
165
166 for (i = 0; i < sys->edges.size(); i++) {
167 idv1 = sys->edges[i][0];
168 idv2 = sys->edges[i][1];
169
170 v1 = sys->vertexCos[idv1];
171 v2 = sys->vertexCos[idv2];
172
173 sys->ne_ed_num[idv1] = sys->ne_ed_num[idv1] + 1;
174 sys->ne_ed_num[idv2] = sys->ne_ed_num[idv2] + 1;
175 w1 = len_v3v3(v1, v2);
176 if (w1 < sys->min_area) {
177 sys->zerola[idv1] = true;
178 sys->zerola[idv2] = true;
179 }
180 else {
181 w1 = 1.0f / w1;
182 }
183
184 sys->eweights[i] = w1;
185 }
186
187 const blender::Span<int> corner_verts = sys->corner_verts;
188
189 for (const int i : sys->faces.index_range()) {
190 const blender::IndexRange face = sys->faces[i];
191 int corner_next = face.start();
192 int corner_term = corner_next + face.size();
193 int corner_prev = corner_term - 2;
194 int corner_curr = corner_term - 1;
195
196 for (; corner_next != corner_term;
197 corner_prev = corner_curr, corner_curr = corner_next, corner_next++)
198 {
199 const float *v_prev = sys->vertexCos[corner_verts[corner_prev]];
200 const float *v_curr = sys->vertexCos[corner_verts[corner_curr]];
201 const float *v_next = sys->vertexCos[corner_verts[corner_next]];
202
203 sys->ne_fa_num[corner_verts[corner_curr]] += 1;
204
205 areaf = area_tri_v3(v_prev, v_curr, v_next);
206
207 if (areaf < sys->min_area) {
208 sys->zerola[corner_verts[corner_curr]] = true;
209 }
210
211 sys->ring_areas[corner_verts[corner_prev]] += areaf;
212 sys->ring_areas[corner_verts[corner_curr]] += areaf;
213 sys->ring_areas[corner_verts[corner_next]] += areaf;
214
215 w1 = cotangent_tri_weight_v3(v_curr, v_next, v_prev) / 2.0f;
216 w2 = cotangent_tri_weight_v3(v_next, v_prev, v_curr) / 2.0f;
217 w3 = cotangent_tri_weight_v3(v_prev, v_curr, v_next) / 2.0f;
218
219 sys->fweights[corner_curr][0] += w1;
220 sys->fweights[corner_curr][1] += w2;
221 sys->fweights[corner_curr][2] += w3;
222
223 sys->vweights[corner_verts[corner_curr]] += w2 + w3;
224 sys->vweights[corner_verts[corner_next]] += w1 + w3;
225 sys->vweights[corner_verts[corner_prev]] += w1 + w2;
226 }
227 }
228 for (i = 0; i < sys->edges.size(); i++) {
229 idv1 = sys->edges[i][0];
230 idv2 = sys->edges[i][1];
231 /* if is boundary, apply scale-dependent umbrella operator only with neighbors in boundary */
232 if (sys->ne_ed_num[idv1] != sys->ne_fa_num[idv1] &&
233 sys->ne_ed_num[idv2] != sys->ne_fa_num[idv2])
234 {
235 sys->vlengths[idv1] += sys->eweights[i];
236 sys->vlengths[idv2] += sys->eweights[i];
237 }
238 }
239}
240
242{
243 int i;
244 uint idv1, idv2;
245
246 const blender::Span<int> corner_verts = sys->corner_verts;
247
248 for (const int i : sys->faces.index_range()) {
249 const blender::IndexRange face = sys->faces[i];
250 int corner_next = face.start();
251 int corner_term = corner_next + face.size();
252 int corner_prev = corner_term - 2;
253 int corner_curr = corner_term - 1;
254
255 for (; corner_next != corner_term;
256 corner_prev = corner_curr, corner_curr = corner_next, corner_next++)
257 {
258
259 /* Is ring if number of faces == number of edges around vertex. */
260 if (sys->ne_ed_num[corner_verts[corner_curr]] == sys->ne_fa_num[corner_verts[corner_curr]] &&
261 sys->zerola[corner_verts[corner_curr]] == false)
262 {
264 corner_verts[corner_curr],
265 corner_verts[corner_next],
266 sys->fweights[corner_curr][2] *
267 sys->vweights[corner_verts[corner_curr]]);
269 corner_verts[corner_curr],
270 corner_verts[corner_prev],
271 sys->fweights[corner_curr][1] *
272 sys->vweights[corner_verts[corner_curr]]);
273 }
274 if (sys->ne_ed_num[corner_verts[corner_next]] == sys->ne_fa_num[corner_verts[corner_next]] &&
275 sys->zerola[corner_verts[corner_next]] == false)
276 {
278 corner_verts[corner_next],
279 corner_verts[corner_curr],
280 sys->fweights[corner_curr][2] *
281 sys->vweights[corner_verts[corner_next]]);
283 corner_verts[corner_next],
284 corner_verts[corner_prev],
285 sys->fweights[corner_curr][0] *
286 sys->vweights[corner_verts[corner_next]]);
287 }
288 if (sys->ne_ed_num[corner_verts[corner_prev]] == sys->ne_fa_num[corner_verts[corner_prev]] &&
289 sys->zerola[corner_verts[corner_prev]] == false)
290 {
292 corner_verts[corner_prev],
293 corner_verts[corner_curr],
294 sys->fweights[corner_curr][1] *
295 sys->vweights[corner_verts[corner_prev]]);
297 corner_verts[corner_prev],
298 corner_verts[corner_next],
299 sys->fweights[corner_curr][0] *
300 sys->vweights[corner_verts[corner_prev]]);
301 }
302 }
303 }
304
305 for (i = 0; i < sys->edges.size(); i++) {
306 idv1 = sys->edges[i][0];
307 idv2 = sys->edges[i][1];
308 /* Is boundary */
309 if (sys->ne_ed_num[idv1] != sys->ne_fa_num[idv1] &&
310 sys->ne_ed_num[idv2] != sys->ne_fa_num[idv2] && sys->zerola[idv1] == false &&
311 sys->zerola[idv2] == false)
312 {
314 sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
316 sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
317 }
318 }
319}
320
321static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border)
322{
323 int i;
324 float lam;
325 float vini = 0.0f, vend = 0.0f;
326
328 vini = compute_volume(sys->vert_centroid, sys->vertexCos, sys->faces, sys->corner_verts);
329 }
330 for (i = 0; i < sys->verts_num; i++) {
331 if (sys->zerola[i] == false) {
332 lam = sys->ne_ed_num[i] == sys->ne_fa_num[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) :
333 (lambda_border >= 0.0f ? 1.0f : -1.0f);
335 sys->vertexCos[i][0] += lam * (float(EIG_linear_solver_variable_get(sys->context, 0, i)) -
336 sys->vertexCos[i][0]);
337 }
339 sys->vertexCos[i][1] += lam * (float(EIG_linear_solver_variable_get(sys->context, 1, i)) -
340 sys->vertexCos[i][1]);
341 }
343 sys->vertexCos[i][2] += lam * (float(EIG_linear_solver_variable_get(sys->context, 2, i)) -
344 sys->vertexCos[i][2]);
345 }
346 }
347 }
349 vend = compute_volume(sys->vert_centroid, sys->vertexCos, sys->faces, sys->corner_verts);
350 volume_preservation(sys, vini, vend, flag);
351 }
352}
353
355 LaplacianSmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int verts_num)
356{
357 LaplacianSystem *sys;
358 const MDeformVert *dvert = nullptr;
359 const MDeformVert *dv = nullptr;
360 float w, wpaint;
361 int i, iter;
362 int defgrp_index;
363 const bool invert_vgroup = (smd->flag & MOD_LAPLACIANSMOOTH_INVERT_VGROUP) != 0;
364
365 sys = init_laplacian_system(mesh->edges_num, mesh->corners_num, verts_num);
366 if (!sys) {
367 return;
368 }
369
370 sys->edges = mesh->edges();
371 sys->faces = mesh->faces();
372 sys->corner_verts = mesh->corner_verts();
373 sys->vertexCos = vertexCos;
374 sys->min_area = 0.00001f;
375 MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
376
377 sys->vert_centroid[0] = 0.0f;
378 sys->vert_centroid[1] = 0.0f;
379 sys->vert_centroid[2] = 0.0f;
381
382 sys->context = EIG_linear_least_squares_solver_new(verts_num, verts_num, 3);
383
385
386 for (iter = 0; iter < smd->repeat; iter++) {
387 for (i = 0; i < verts_num; i++) {
388 EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]);
389 EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]);
390 EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]);
391 if (iter == 0) {
392 add_v3_v3(sys->vert_centroid, vertexCos[i]);
393 }
394 }
395 if (iter == 0 && verts_num > 0) {
396 mul_v3_fl(sys->vert_centroid, 1.0f / float(verts_num));
397 }
398
399 dv = dvert;
400 for (i = 0; i < verts_num; i++) {
401 EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]);
402 EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]);
403 EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]);
404 if (iter == 0) {
405 if (dv) {
406 wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
407 BKE_defvert_find_weight(dv, defgrp_index);
408 dv++;
409 }
410 else {
411 wpaint = 1.0f;
412 }
413
414 if (sys->zerola[i] == false) {
416 w = sys->vweights[i];
417 sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w;
418 w = sys->vlengths[i];
419 sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
420 if (sys->ne_ed_num[i] == sys->ne_fa_num[i]) {
421 EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint);
422 }
423 else {
425 sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
426 }
427 }
428 else {
429 w = sys->vweights[i] * sys->ring_areas[i];
430 sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w);
431 w = sys->vlengths[i];
432 sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
433
434 if (sys->ne_ed_num[i] == sys->ne_fa_num[i]) {
436 i,
437 i,
438 1.0f + fabsf(smd->lambda) * wpaint /
439 (4.0f * sys->ring_areas[i]));
440 }
441 else {
443 sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
444 }
445 }
446 }
447 else {
449 }
450 }
451 }
452
453 if (iter == 0) {
455 }
456
458 validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
459 }
460 }
462 sys->context = nullptr;
463
465}
466
475
476static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
477{
479 short flag;
480
482
483 /* disable if modifier is off for X, Y and Z or if factor is 0 */
484 if (flag == 0) {
485 return true;
486 }
487
488 return false;
489}
490
491static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
492{
494
495 /* Ask for vertex-groups if we need them. */
496 if (smd->defgrp_name[0] != '\0') {
497 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
498 }
499}
500
502 const ModifierEvalContext *ctx,
503 Mesh *mesh,
505{
506 if (positions.is_empty()) {
507 return;
508 }
509
511 ctx->object,
512 mesh,
513 reinterpret_cast<float(*)[3]>(positions.data()),
514 positions.size());
515}
516
517static void panel_draw(const bContext * /*C*/, Panel *panel)
518{
519 uiLayout *row;
520 uiLayout *layout = panel->layout;
522
523 PointerRNA ob_ptr;
525
526 uiLayoutSetPropSep(layout, true);
527
528 layout->prop(ptr, "iterations", UI_ITEM_NONE, std::nullopt, ICON_NONE);
529
530 row = &layout->row(true, IFACE_("Axis"));
531 row->prop(ptr, "use_x", toggles_flag, std::nullopt, ICON_NONE);
532 row->prop(ptr, "use_y", toggles_flag, std::nullopt, ICON_NONE);
533 row->prop(ptr, "use_z", toggles_flag, std::nullopt, ICON_NONE);
534
535 layout->prop(ptr, "lambda_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
536 layout->prop(ptr, "lambda_border", UI_ITEM_NONE, std::nullopt, ICON_NONE);
537
538 layout->prop(ptr, "use_volume_preserve", UI_ITEM_NONE, std::nullopt, ICON_NONE);
539 layout->prop(ptr, "use_normalized", UI_ITEM_NONE, std::nullopt, ICON_NONE);
540
541 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
542
544}
545
546static void panel_register(ARegionType *region_type)
547{
549}
550
552 /*idname*/ "LaplacianSmooth",
553 /*name*/ N_("LaplacianSmooth"),
554 /*struct_name*/ "LaplacianSmoothModifierData",
555 /*struct_size*/ sizeof(LaplacianSmoothModifierData),
556 /*srna*/ &RNA_LaplacianSmoothModifier,
559 /*icon*/ ICON_MOD_SMOOTH,
560
561 /*copy_data*/ BKE_modifier_copydata_generic,
562
563 /*deform_verts*/ deform_verts,
564 /*deform_matrices*/ nullptr,
565 /*deform_verts_EM*/ nullptr,
566 /*deform_matrices_EM*/ nullptr,
567 /*modify_mesh*/ nullptr,
568 /*modify_geometry_set*/ nullptr,
569
570 /*init_data*/ init_data,
571 /*required_data_mask*/ required_data_mask,
572 /*free_data*/ nullptr,
573 /*is_disabled*/ is_disabled,
574 /*update_depsgraph*/ nullptr,
575 /*depends_on_time*/ nullptr,
576 /*depends_on_normals*/ nullptr,
577 /*foreach_ID_link*/ nullptr,
578 /*foreach_tex_link*/ nullptr,
579 /*free_runtime_data*/ nullptr,
580 /*panel_register*/ panel_register,
581 /*blend_write*/ nullptr,
582 /*blend_read*/ nullptr,
583 /*foreach_cache*/ nullptr,
584};
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:763
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
#define BLI_assert(a)
Definition BLI_assert.h:46
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:100
float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:251
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:198
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
#define DNA_struct_default_get(struct_name)
@ MOD_LAPLACIANSMOOTH_X
@ MOD_LAPLACIANSMOOTH_Y
@ MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME
@ MOD_LAPLACIANSMOOTH_NORMALIZED
@ MOD_LAPLACIANSMOOTH_Z
@ MOD_LAPLACIANSMOOTH_INVERT_VGROUP
@ eModifierType_LaplacianSmooth
static bool is_disabled
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void panel_draw(const bContext *, Panel *panel)
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void panel_register(ARegionType *region_type)
static void laplaciansmoothModifier_do(LaplacianSmoothModifierData *smd, Object *ob, Mesh *mesh, float(*vertexCos)[3], int verts_num)
ModifierTypeInfo modifierType_LaplacianSmooth
static void init_laplacian_matrix(LaplacianSystem *sys)
static void delete_laplacian_system(LaplacianSystem *sys)
static LaplacianSystem * init_laplacian_system(int a_numEdges, int a_numLoops, int a_numVerts)
static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag)
static void memset_laplacian_system(LaplacianSystem *sys, int val)
static void panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border)
static void fill_laplacian_matrix(LaplacianSystem *sys)
static float compute_volume(const float center[3], float(*vertexCos)[3], const blender::OffsetIndices< int > faces, const blender::Span< int > corner_verts)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const StringRefNull vgroup_prop, const std::optional< StringRefNull > invert_vgroup_prop, const std::optional< StringRefNull > text)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:156
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr T * data() const
Definition BLI_span.hh:539
#define fabsf(x)
#define pow
#define CD_MASK_MDEFORMVERT
#define MEM_SAFE_FREE(v)
void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
LinearSolver * EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_right_hand_sides)
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 * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
ccl_device_inline float beta(const float x, const float y)
Definition math_base.h:651
static char faces[256]
float(* fweights)[3]
LinearSolver * context
int corners_num
int edges_num
struct uiLayout * layout
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4227
uint8_t flag
Definition wm_window.cc:139