Blender V5.0
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
25#include "UI_resources.hh"
26
27#include "RNA_prototypes.hh"
28#include "RNA_types.hh"
29
30#include "MOD_ui_common.hh"
31#include "MOD_util.hh"
32
33#include "eigen_capi.h"
34
35namespace {
36
37struct LaplacianSystem {
38 float *eweights = nullptr; /* Length weights per Edge */
39 float (*fweights)[3] = nullptr; /* Cotangent weights per face */
40 float *ring_areas = nullptr; /* Total area per ring. */
41 float *vlengths = nullptr; /* Total sum of lengths(edges) per vertex. */
42 float *vweights = nullptr; /* Total sum of weights per vertex. */
43 int verts_num = 0; /* Number of verts. */
44 short *ne_fa_num = nullptr; /* Number of neighbors faces around vertex. */
45 short *ne_ed_num = nullptr; /* Number of neighbors Edges around vertex. */
46 bool *zerola = nullptr; /* Is zero area or length. */
47
48 /* Pointers to data. */
49 float (*vertexCos)[3] = nullptr;
50 blender::Span<blender::int2> edges = {};
51 blender::OffsetIndices<int> faces = {};
52 blender::Span<int> corner_verts = {};
53 LinearSolver *context = nullptr;
54
55 /* Data. */
56 float min_area = 0.0f;
57 float vert_centroid[3] = {};
58};
59
60}; // namespace
61
63{
64 MEM_SAFE_FREE(sys->eweights);
66 MEM_SAFE_FREE(sys->ne_ed_num);
67 MEM_SAFE_FREE(sys->ne_fa_num);
68 MEM_SAFE_FREE(sys->ring_areas);
69 MEM_SAFE_FREE(sys->vlengths);
70 MEM_SAFE_FREE(sys->vweights);
71 MEM_SAFE_FREE(sys->zerola);
72
73 if (sys->context) {
75 }
76 sys->vertexCos = nullptr;
77 MEM_delete(sys);
78}
79
80static void memset_laplacian_system(LaplacianSystem *sys, int val)
81{
82 memset(sys->eweights, val, sizeof(float) * sys->edges.size());
83 memset(sys->fweights, val, sizeof(float[3]) * sys->corner_verts.size());
84 memset(sys->ne_ed_num, val, sizeof(short) * sys->verts_num);
85 memset(sys->ne_fa_num, val, sizeof(short) * sys->verts_num);
86 memset(sys->ring_areas, val, sizeof(float) * sys->verts_num);
87 memset(sys->vlengths, val, sizeof(float) * sys->verts_num);
88 memset(sys->vweights, val, sizeof(float) * sys->verts_num);
89 memset(sys->zerola, val, sizeof(bool) * sys->verts_num);
90}
91
92static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numLoops, int a_numVerts)
93{
94 LaplacianSystem *sys;
95 sys = MEM_new<LaplacianSystem>(__func__);
96 sys->verts_num = a_numVerts;
97
98 sys->eweights = MEM_calloc_arrayN<float>(a_numEdges, __func__);
99 sys->fweights = MEM_calloc_arrayN<float[3]>(a_numLoops, __func__);
100 sys->ne_ed_num = MEM_calloc_arrayN<short>(sys->verts_num, __func__);
101 sys->ne_fa_num = MEM_calloc_arrayN<short>(sys->verts_num, __func__);
102 sys->ring_areas = MEM_calloc_arrayN<float>(sys->verts_num, __func__);
103 sys->vlengths = MEM_calloc_arrayN<float>(sys->verts_num, __func__);
104 sys->vweights = MEM_calloc_arrayN<float>(sys->verts_num, __func__);
105 sys->zerola = MEM_calloc_arrayN<bool>(sys->verts_num, __func__);
106
107 return sys;
108}
109
110static float compute_volume(const float center[3],
111 float (*vertexCos)[3],
113 const blender::Span<int> corner_verts)
114{
115 float vol = 0.0f;
116
117 for (const int i : faces.index_range()) {
118 const blender::IndexRange face = faces[i];
119 int corner_first = face.start();
120 int corner_prev = corner_first + 1;
121 int corner_curr = corner_first + 2;
122 int corner_term = corner_first + face.size();
123
124 for (; corner_curr != corner_term; corner_prev = corner_curr, corner_curr++) {
125 vol += volume_tetrahedron_signed_v3(center,
126 vertexCos[corner_verts[corner_first]],
127 vertexCos[corner_verts[corner_prev]],
128 vertexCos[corner_verts[corner_curr]]);
129 }
130 }
131
132 return fabsf(vol);
133}
134
135static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag)
136{
137 float beta;
138 int i;
139
140 if (vend != 0.0f) {
141 beta = pow(vini / vend, 1.0f / 3.0f);
142 for (i = 0; i < sys->verts_num; i++) {
144 sys->vertexCos[i][0] = (sys->vertexCos[i][0] - sys->vert_centroid[0]) * beta +
145 sys->vert_centroid[0];
146 }
148 sys->vertexCos[i][1] = (sys->vertexCos[i][1] - sys->vert_centroid[1]) * beta +
149 sys->vert_centroid[1];
150 }
152 sys->vertexCos[i][2] = (sys->vertexCos[i][2] - sys->vert_centroid[2]) * beta +
153 sys->vert_centroid[2];
154 }
155 }
156 }
157}
158
160{
161 float *v1, *v2;
162 float w1, w2, w3;
163 float areaf;
164 int i;
165 uint idv1, idv2;
166
167 for (i = 0; i < sys->edges.size(); i++) {
168 idv1 = sys->edges[i][0];
169 idv2 = sys->edges[i][1];
170
171 v1 = sys->vertexCos[idv1];
172 v2 = sys->vertexCos[idv2];
173
174 sys->ne_ed_num[idv1] = sys->ne_ed_num[idv1] + 1;
175 sys->ne_ed_num[idv2] = sys->ne_ed_num[idv2] + 1;
176 w1 = len_v3v3(v1, v2);
177 if (w1 < sys->min_area) {
178 sys->zerola[idv1] = true;
179 sys->zerola[idv2] = true;
180 }
181 else {
182 w1 = 1.0f / w1;
183 }
184
185 sys->eweights[i] = w1;
186 }
187
188 const blender::Span<int> corner_verts = sys->corner_verts;
189
190 for (const int i : sys->faces.index_range()) {
191 const blender::IndexRange face = sys->faces[i];
192 int corner_next = face.start();
193 int corner_term = corner_next + face.size();
194 int corner_prev = corner_term - 2;
195 int corner_curr = corner_term - 1;
196
197 for (; corner_next != corner_term;
198 corner_prev = corner_curr, corner_curr = corner_next, corner_next++)
199 {
200 const float *v_prev = sys->vertexCos[corner_verts[corner_prev]];
201 const float *v_curr = sys->vertexCos[corner_verts[corner_curr]];
202 const float *v_next = sys->vertexCos[corner_verts[corner_next]];
203
204 sys->ne_fa_num[corner_verts[corner_curr]] += 1;
205
206 areaf = area_tri_v3(v_prev, v_curr, v_next);
207
208 if (areaf < sys->min_area) {
209 sys->zerola[corner_verts[corner_curr]] = true;
210 }
211
212 sys->ring_areas[corner_verts[corner_prev]] += areaf;
213 sys->ring_areas[corner_verts[corner_curr]] += areaf;
214 sys->ring_areas[corner_verts[corner_next]] += areaf;
215
216 w1 = cotangent_tri_weight_v3(v_curr, v_next, v_prev) / 2.0f;
217 w2 = cotangent_tri_weight_v3(v_next, v_prev, v_curr) / 2.0f;
218 w3 = cotangent_tri_weight_v3(v_prev, v_curr, v_next) / 2.0f;
219
220 sys->fweights[corner_curr][0] += w1;
221 sys->fweights[corner_curr][1] += w2;
222 sys->fweights[corner_curr][2] += w3;
223
224 sys->vweights[corner_verts[corner_curr]] += w2 + w3;
225 sys->vweights[corner_verts[corner_next]] += w1 + w3;
226 sys->vweights[corner_verts[corner_prev]] += w1 + w2;
227 }
228 }
229 for (i = 0; i < sys->edges.size(); i++) {
230 idv1 = sys->edges[i][0];
231 idv2 = sys->edges[i][1];
232 /* if is boundary, apply scale-dependent umbrella operator only with neighbors in boundary */
233 if (sys->ne_ed_num[idv1] != sys->ne_fa_num[idv1] &&
234 sys->ne_ed_num[idv2] != sys->ne_fa_num[idv2])
235 {
236 sys->vlengths[idv1] += sys->eweights[i];
237 sys->vlengths[idv2] += sys->eweights[i];
238 }
239 }
240}
241
243{
244 int i;
245 uint idv1, idv2;
246
247 const blender::Span<int> corner_verts = sys->corner_verts;
248
249 for (const int i : sys->faces.index_range()) {
250 const blender::IndexRange face = sys->faces[i];
251 int corner_next = face.start();
252 int corner_term = corner_next + face.size();
253 int corner_prev = corner_term - 2;
254 int corner_curr = corner_term - 1;
255
256 for (; corner_next != corner_term;
257 corner_prev = corner_curr, corner_curr = corner_next, corner_next++)
258 {
259
260 /* Is ring if number of faces == number of edges around vertex. */
261 if (sys->ne_ed_num[corner_verts[corner_curr]] == sys->ne_fa_num[corner_verts[corner_curr]] &&
262 sys->zerola[corner_verts[corner_curr]] == false)
263 {
265 corner_verts[corner_curr],
266 corner_verts[corner_next],
267 sys->fweights[corner_curr][2] *
268 sys->vweights[corner_verts[corner_curr]]);
270 corner_verts[corner_curr],
271 corner_verts[corner_prev],
272 sys->fweights[corner_curr][1] *
273 sys->vweights[corner_verts[corner_curr]]);
274 }
275 if (sys->ne_ed_num[corner_verts[corner_next]] == sys->ne_fa_num[corner_verts[corner_next]] &&
276 sys->zerola[corner_verts[corner_next]] == false)
277 {
279 corner_verts[corner_next],
280 corner_verts[corner_curr],
281 sys->fweights[corner_curr][2] *
282 sys->vweights[corner_verts[corner_next]]);
284 corner_verts[corner_next],
285 corner_verts[corner_prev],
286 sys->fweights[corner_curr][0] *
287 sys->vweights[corner_verts[corner_next]]);
288 }
289 if (sys->ne_ed_num[corner_verts[corner_prev]] == sys->ne_fa_num[corner_verts[corner_prev]] &&
290 sys->zerola[corner_verts[corner_prev]] == false)
291 {
293 corner_verts[corner_prev],
294 corner_verts[corner_curr],
295 sys->fweights[corner_curr][1] *
296 sys->vweights[corner_verts[corner_prev]]);
298 corner_verts[corner_prev],
299 corner_verts[corner_next],
300 sys->fweights[corner_curr][0] *
301 sys->vweights[corner_verts[corner_prev]]);
302 }
303 }
304 }
305
306 for (i = 0; i < sys->edges.size(); i++) {
307 idv1 = sys->edges[i][0];
308 idv2 = sys->edges[i][1];
309 /* Is boundary */
310 if (sys->ne_ed_num[idv1] != sys->ne_fa_num[idv1] &&
311 sys->ne_ed_num[idv2] != sys->ne_fa_num[idv2] && sys->zerola[idv1] == false &&
312 sys->zerola[idv2] == false)
313 {
315 sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
317 sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
318 }
319 }
320}
321
322static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border)
323{
324 int i;
325 float lam;
326 float vini = 0.0f, vend = 0.0f;
327
329 vini = compute_volume(sys->vert_centroid, sys->vertexCos, sys->faces, sys->corner_verts);
330 }
331 for (i = 0; i < sys->verts_num; i++) {
332 if (sys->zerola[i] == false) {
333 lam = sys->ne_ed_num[i] == sys->ne_fa_num[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) :
334 (lambda_border >= 0.0f ? 1.0f : -1.0f);
336 sys->vertexCos[i][0] += lam * (float(EIG_linear_solver_variable_get(sys->context, 0, i)) -
337 sys->vertexCos[i][0]);
338 }
340 sys->vertexCos[i][1] += lam * (float(EIG_linear_solver_variable_get(sys->context, 1, i)) -
341 sys->vertexCos[i][1]);
342 }
344 sys->vertexCos[i][2] += lam * (float(EIG_linear_solver_variable_get(sys->context, 2, i)) -
345 sys->vertexCos[i][2]);
346 }
347 }
348 }
350 vend = compute_volume(sys->vert_centroid, sys->vertexCos, sys->faces, sys->corner_verts);
351 volume_preservation(sys, vini, vend, flag);
352 }
353}
354
356 LaplacianSmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int verts_num)
357{
358 LaplacianSystem *sys;
359 const MDeformVert *dvert = nullptr;
360 const MDeformVert *dv = nullptr;
361 float w, wpaint;
362 int i, iter;
363 int defgrp_index;
364 const bool invert_vgroup = (smd->flag & MOD_LAPLACIANSMOOTH_INVERT_VGROUP) != 0;
365
366 sys = init_laplacian_system(mesh->edges_num, mesh->corners_num, verts_num);
367 if (!sys) {
368 return;
369 }
370
371 sys->edges = mesh->edges();
372 sys->faces = mesh->faces();
373 sys->corner_verts = mesh->corner_verts();
374 sys->vertexCos = vertexCos;
375 sys->min_area = 0.00001f;
376 MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
377
378 sys->vert_centroid[0] = 0.0f;
379 sys->vert_centroid[1] = 0.0f;
380 sys->vert_centroid[2] = 0.0f;
382
383 sys->context = EIG_linear_least_squares_solver_new(verts_num, verts_num, 3);
384
386
387 for (iter = 0; iter < smd->repeat; iter++) {
388 for (i = 0; i < verts_num; i++) {
389 EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]);
390 EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]);
391 EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]);
392 if (iter == 0) {
393 add_v3_v3(sys->vert_centroid, vertexCos[i]);
394 }
395 }
396 if (iter == 0 && verts_num > 0) {
397 mul_v3_fl(sys->vert_centroid, 1.0f / float(verts_num));
398 }
399
400 dv = dvert;
401 for (i = 0; i < verts_num; i++) {
402 EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]);
403 EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]);
404 EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]);
405 if (iter == 0) {
406 if (dv) {
407 wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
408 BKE_defvert_find_weight(dv, defgrp_index);
409 dv++;
410 }
411 else {
412 wpaint = 1.0f;
413 }
414
415 if (sys->zerola[i] == false) {
417 w = sys->vweights[i];
418 sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w;
419 w = sys->vlengths[i];
420 sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
421 if (sys->ne_ed_num[i] == sys->ne_fa_num[i]) {
422 EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint);
423 }
424 else {
426 sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
427 }
428 }
429 else {
430 w = sys->vweights[i] * sys->ring_areas[i];
431 sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w);
432 w = sys->vlengths[i];
433 sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
434
435 if (sys->ne_ed_num[i] == sys->ne_fa_num[i]) {
437 i,
438 i,
439 1.0f + fabsf(smd->lambda) * wpaint /
440 (4.0f * sys->ring_areas[i]));
441 }
442 else {
444 sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
445 }
446 }
447 }
448 else {
450 }
451 }
452 }
453
454 if (iter == 0) {
456 }
457
459 validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
460 }
461 }
463 sys->context = nullptr;
464
466}
467
476
477static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
478{
480 short flag;
481
483
484 /* disable if modifier is off for X, Y and Z or if factor is 0 */
485 if (flag == 0) {
486 return true;
487 }
488
489 return false;
490}
491
492static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
493{
495
496 /* Ask for vertex-groups if we need them. */
497 if (smd->defgrp_name[0] != '\0') {
498 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
499 }
500}
501
503 const ModifierEvalContext *ctx,
504 Mesh *mesh,
506{
507 if (positions.is_empty()) {
508 return;
509 }
510
512 ctx->object,
513 mesh,
514 reinterpret_cast<float (*)[3]>(positions.data()),
515 positions.size());
516}
517
518static void panel_draw(const bContext * /*C*/, Panel *panel)
519{
520 uiLayout *row;
521 uiLayout *layout = panel->layout;
523
524 PointerRNA ob_ptr;
526
527 layout->use_property_split_set(true);
528
529 layout->prop(ptr, "iterations", UI_ITEM_NONE, std::nullopt, ICON_NONE);
530
531 row = &layout->row(true, IFACE_("Axis"));
532 row->prop(ptr, "use_x", toggles_flag, std::nullopt, ICON_NONE);
533 row->prop(ptr, "use_y", toggles_flag, std::nullopt, ICON_NONE);
534 row->prop(ptr, "use_z", toggles_flag, std::nullopt, ICON_NONE);
535
536 layout->prop(ptr, "lambda_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
537 layout->prop(ptr, "lambda_border", UI_ITEM_NONE, std::nullopt, ICON_NONE);
538
539 layout->prop(ptr, "use_volume_preserve", UI_ITEM_NONE, std::nullopt, ICON_NONE);
540 layout->prop(ptr, "use_normalized", UI_ITEM_NONE, std::nullopt, ICON_NONE);
541
542 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
543
545}
546
547static void panel_register(ARegionType *region_type)
548{
550}
551
553 /*idname*/ "LaplacianSmooth",
554 /*name*/ N_("LaplacianSmooth"),
555 /*struct_name*/ "LaplacianSmoothModifierData",
556 /*struct_size*/ sizeof(LaplacianSmoothModifierData),
557 /*srna*/ &RNA_LaplacianSmoothModifier,
560 /*icon*/ ICON_MOD_SMOOTH,
561
562 /*copy_data*/ BKE_modifier_copydata_generic,
563
564 /*deform_verts*/ deform_verts,
565 /*deform_matrices*/ nullptr,
566 /*deform_verts_EM*/ nullptr,
567 /*deform_matrices_EM*/ nullptr,
568 /*modify_mesh*/ nullptr,
569 /*modify_geometry_set*/ nullptr,
570
571 /*init_data*/ init_data,
572 /*required_data_mask*/ required_data_mask,
573 /*free_data*/ nullptr,
574 /*is_disabled*/ is_disabled,
575 /*update_depsgraph*/ nullptr,
576 /*depends_on_time*/ nullptr,
577 /*depends_on_normals*/ nullptr,
578 /*foreach_ID_link*/ nullptr,
579 /*foreach_tex_link*/ nullptr,
580 /*free_runtime_data*/ nullptr,
581 /*panel_register*/ panel_register,
582 /*blend_write*/ nullptr,
583 /*blend_read*/ nullptr,
584 /*foreach_cache*/ nullptr,
585 /*foreach_working_space_color*/ nullptr,
586};
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
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 CD_MASK_MDEFORMVERT
#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.
#define MEM_SAFE_FREE(v)
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
#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
nullptr float
#define pow
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:661
static char faces[256]
#define fabsf
float(* fweights)[3]
LinearSolver * context
int corners_num
int edges_num
struct uiLayout * layout
uiLayout & row(bool align)
void use_property_split_set(bool value)
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:4238
uint8_t flag
Definition wm_window.cc:145