Blender V5.0
MOD_laplaciandeform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_utildefines.h"
10
11#include "BLI_math_geom.h"
12#include "BLI_math_vector.h"
13#include "BLI_string.h"
15
16#include "MEM_guardedalloc.h"
17
18#include "BLT_translation.hh"
19
20#include "DNA_defaults.h"
21#include "DNA_mesh_types.h"
22#include "DNA_meshdata_types.h"
23#include "DNA_screen_types.h"
24
25#include "BKE_deform.hh"
26#include "BKE_mesh_mapping.hh"
27
29#include "UI_resources.hh"
30
31#include "BLO_read_write.hh"
32
33#include "RNA_access.hh"
34#include "RNA_prototypes.hh"
35
36#include "MOD_ui_common.hh"
37#include "MOD_util.hh"
38
39#include "eigen_capi.h"
40
41enum {
50};
51
52namespace {
53
54struct LaplacianSystem {
55 bool is_matrix_computed;
56 bool has_solution;
57 int verts_num;
58 int edges_num;
59 int tris_num;
60 int anchors_num;
61 int repeat;
63 char anchor_grp_name[/*MAX_VGROUP_NAME*/ 64];
65 float (*co)[3];
67 float (*no)[3];
69 float (*delta)[3];
75 uint (*tris)[3];
77 int *index_anchors;
79 int *unit_verts;
81 int *ringf_indices;
83 int *ringv_indices;
85 LinearSolver *context;
87 MeshElemMap *ringf_map;
89 MeshElemMap *ringv_map;
90};
91
92}; // namespace
93
95{
97
98 sys->is_matrix_computed = false;
99 sys->has_solution = false;
100 sys->verts_num = 0;
101 sys->edges_num = 0;
102 sys->anchors_num = 0;
103 sys->tris_num = 0;
104 sys->repeat = 1;
105 sys->anchor_grp_name[0] = '\0';
106
107 return sys;
108}
109
111 int edges_num,
112 int tris_num,
113 int anchors_num,
114 const char defgrpName[64],
115 int iterations)
116{
118
119 sys->is_matrix_computed = false;
120 sys->has_solution = false;
121 sys->verts_num = verts_num;
122 sys->edges_num = edges_num;
123 sys->tris_num = tris_num;
124 sys->anchors_num = anchors_num;
125 sys->repeat = iterations;
126 STRNCPY(sys->anchor_grp_name, defgrpName);
127 sys->co = MEM_malloc_arrayN<float[3]>(size_t(verts_num), __func__);
128 sys->no = MEM_calloc_arrayN<float[3]>(verts_num, __func__);
129 sys->delta = MEM_calloc_arrayN<float[3]>(verts_num, __func__);
130 sys->tris = MEM_malloc_arrayN<uint[3]>(size_t(tris_num), __func__);
131 sys->index_anchors = MEM_malloc_arrayN<int>(size_t(anchors_num), __func__);
132 sys->unit_verts = MEM_calloc_arrayN<int>(verts_num, __func__);
133 return sys;
134}
135
137{
138 MEM_SAFE_FREE(sys->co);
139 MEM_SAFE_FREE(sys->no);
140 MEM_SAFE_FREE(sys->delta);
141 MEM_SAFE_FREE(sys->tris);
142 MEM_SAFE_FREE(sys->index_anchors);
143 MEM_SAFE_FREE(sys->unit_verts);
144 MEM_SAFE_FREE(sys->ringf_indices);
145 MEM_SAFE_FREE(sys->ringv_indices);
146 MEM_SAFE_FREE(sys->ringf_map);
147 MEM_SAFE_FREE(sys->ringv_map);
148
149 if (sys->context) {
151 }
152 MEM_SAFE_FREE(sys);
153}
154
155static void createFaceRingMap(const int mvert_tot,
157 blender::Span<int> corner_verts,
158 MeshElemMap **r_map,
159 int **r_indices)
160{
161 int indices_num = 0;
162 int *indices, *index_iter;
163 MeshElemMap *map = MEM_calloc_arrayN<MeshElemMap>(mvert_tot, __func__);
164
165 for (const int i : corner_tris.index_range()) {
166 const blender::int3 &tri = corner_tris[i];
167 for (int j = 0; j < 3; j++) {
168 const int v_index = corner_verts[tri[j]];
169 map[v_index].count++;
170 indices_num++;
171 }
172 }
173 indices = MEM_calloc_arrayN<int>(indices_num, __func__);
174 index_iter = indices;
175 for (int i = 0; i < mvert_tot; i++) {
176 map[i].indices = index_iter;
177 index_iter += map[i].count;
178 map[i].count = 0;
179 }
180 for (const int i : corner_tris.index_range()) {
181 const blender::int3 &tri = corner_tris[i];
182 for (int j = 0; j < 3; j++) {
183 const int v_index = corner_verts[tri[j]];
184 map[v_index].indices[map[v_index].count] = i;
185 map[v_index].count++;
186 }
187 }
188 *r_map = map;
189 *r_indices = indices;
190}
191
192static void createVertRingMap(const int mvert_tot,
194 MeshElemMap **r_map,
195 int **r_indices)
196{
197 MeshElemMap *map = MEM_calloc_arrayN<MeshElemMap>(mvert_tot, __func__);
198 int i, vid[2], indices_num = 0;
199 int *indices, *index_iter;
200
201 for (const int i : edges.index_range()) {
202 vid[0] = edges[i][0];
203 vid[1] = edges[i][1];
204 map[vid[0]].count++;
205 map[vid[1]].count++;
206 indices_num += 2;
207 }
208 indices = MEM_calloc_arrayN<int>(indices_num, __func__);
209 index_iter = indices;
210 for (i = 0; i < mvert_tot; i++) {
211 map[i].indices = index_iter;
212 index_iter += map[i].count;
213 map[i].count = 0;
214 }
215 for (const int i : edges.index_range()) {
216 vid[0] = edges[i][0];
217 vid[1] = edges[i][1];
218 map[vid[0]].indices[map[vid[0]].count] = vid[1];
219 map[vid[0]].count++;
220 map[vid[1]].indices[map[vid[1]].count] = vid[0];
221 map[vid[1]].count++;
222 }
223 *r_map = map;
224 *r_indices = indices;
225}
226
260{
261 float no[3];
262 float w2, w3;
263 int i = 3, j, ti;
264 int idv[3];
265
266 for (ti = 0; ti < sys->tris_num; ti++) {
267 const uint *vidt = sys->tris[ti];
268 const float *co[3];
269
270 co[0] = sys->co[vidt[0]];
271 co[1] = sys->co[vidt[1]];
272 co[2] = sys->co[vidt[2]];
273
274 normal_tri_v3(no, UNPACK3(co));
275 add_v3_v3(sys->no[vidt[0]], no);
276 add_v3_v3(sys->no[vidt[1]], no);
277 add_v3_v3(sys->no[vidt[2]], no);
278
279 for (j = 0; j < 3; j++) {
280 const float *v1, *v2, *v3;
281
282 idv[0] = vidt[j];
283 idv[1] = vidt[(j + 1) % i];
284 idv[2] = vidt[(j + 2) % i];
285
286 v1 = sys->co[idv[0]];
287 v2 = sys->co[idv[1]];
288 v3 = sys->co[idv[2]];
289
290 w2 = cotangent_tri_weight_v3(v3, v1, v2);
291 w3 = cotangent_tri_weight_v3(v2, v3, v1);
292
293 sys->delta[idv[0]][0] += v1[0] * (w2 + w3);
294 sys->delta[idv[0]][1] += v1[1] * (w2 + w3);
295 sys->delta[idv[0]][2] += v1[2] * (w2 + w3);
296
297 sys->delta[idv[0]][0] -= v2[0] * w2;
298 sys->delta[idv[0]][1] -= v2[1] * w2;
299 sys->delta[idv[0]][2] -= v2[2] * w2;
300
301 sys->delta[idv[0]][0] -= v3[0] * w3;
302 sys->delta[idv[0]][1] -= v3[1] * w3;
303 sys->delta[idv[0]][2] -= v3[2] * w3;
304
305 EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2);
306 EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3);
307 EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3);
308 }
309 }
310}
311
313{
314 int vid, *vidn = nullptr;
315 float minj, mjt, qj[3], vj[3];
316 int i, j, ln;
317
318 for (i = 0; i < sys->verts_num; i++) {
319 normalize_v3(sys->no[i]);
320 vidn = sys->ringv_map[i].indices;
321 ln = sys->ringv_map[i].count;
322 minj = 1000000.0f;
323 for (j = 0; j < ln; j++) {
324 vid = vidn[j];
325 copy_v3_v3(qj, sys->co[vid]);
326 sub_v3_v3v3(vj, qj, sys->co[i]);
327 normalize_v3(vj);
328 mjt = fabsf(dot_v3v3(vj, sys->no[i]));
329 if (mjt < minj) {
330 minj = mjt;
331 sys->unit_verts[i] = vidn[j];
332 }
333 }
334 }
335}
336
338{
339 float alpha, beta, gamma;
340 float pj[3], ni[3], di[3];
341 float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3];
342 int i, j, fidn_num, k, fi;
343 int *fidn;
344
345 for (i = 0; i < sys->verts_num; i++) {
346 copy_v3_v3(pi, sys->co[i]);
347 copy_v3_v3(ni, sys->no[i]);
348 k = sys->unit_verts[i];
349 copy_v3_v3(pj, sys->co[k]);
350 sub_v3_v3v3(uij, pj, pi);
351 mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
352 sub_v3_v3(uij, dun);
353 normalize_v3(uij);
354 cross_v3_v3v3(e2, ni, uij);
355 copy_v3_v3(di, sys->delta[i]);
356 alpha = dot_v3v3(ni, di);
357 beta = dot_v3v3(uij, di);
358 gamma = dot_v3v3(e2, di);
359
360 pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i);
361 pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i);
362 pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i);
363 zero_v3(ni);
364 fidn_num = sys->ringf_map[i].count;
365 for (fi = 0; fi < fidn_num; fi++) {
366 const uint *vin;
367 fidn = sys->ringf_map[i].indices;
368 vin = sys->tris[fidn[fi]];
369 for (j = 0; j < 3; j++) {
370 vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]);
371 vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]);
372 vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]);
373 if (vin[j] == sys->unit_verts[i]) {
374 copy_v3_v3(pj, vn[j]);
375 }
376 }
377
378 normal_tri_v3(fni, UNPACK3(vn));
379 add_v3_v3(ni, fni);
380 }
381
382 normalize_v3(ni);
383 sub_v3_v3v3(uij, pj, pi);
384 mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
385 sub_v3_v3(uij, dun);
386 normalize_v3(uij);
387 cross_v3_v3v3(e2, ni, uij);
388 fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0];
389 fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1];
390 fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];
391
392 if (len_squared_v3(fni) > FLT_EPSILON) {
396 }
397 else {
398 EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
399 EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
400 EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
401 }
402 }
403}
404
405static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
406{
407 int vid, i, j, n, na;
408 n = sys->verts_num;
409 na = sys->anchors_num;
410
411 if (!sys->is_matrix_computed) {
412 sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3);
413
414 for (i = 0; i < n; i++) {
415 EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]);
416 EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]);
417 EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]);
418 }
419 for (i = 0; i < na; i++) {
420 vid = sys->index_anchors[i];
421 EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]);
422 EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]);
423 EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]);
424 }
425
428
429 for (i = 0; i < n; i++) {
430 EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
431 EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
432 EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
433 }
434 for (i = 0; i < na; i++) {
435 vid = sys->index_anchors[i];
436 EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
437 EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
438 EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
439 EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
440 }
442 sys->has_solution = true;
443
444 for (j = 1; j <= sys->repeat; j++) {
446
447 for (i = 0; i < na; i++) {
448 vid = sys->index_anchors[i];
449 EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
450 EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
451 EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
452 }
453
454 if (!EIG_linear_solver_solve(sys->context)) {
455 sys->has_solution = false;
456 break;
457 }
458 }
459 if (sys->has_solution) {
460 for (vid = 0; vid < sys->verts_num; vid++) {
461 vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
462 vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
463 vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
464 }
465 }
466 else {
467 sys->has_solution = false;
468 }
469 }
470 else {
471 sys->has_solution = false;
472 }
473 sys->is_matrix_computed = true;
474 }
475 else if (sys->has_solution) {
476 for (i = 0; i < n; i++) {
477 EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
478 EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
479 EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
480 }
481 for (i = 0; i < na; i++) {
482 vid = sys->index_anchors[i];
483 EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
484 EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
485 EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
486 EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
487 }
488
490 sys->has_solution = true;
491 for (j = 1; j <= sys->repeat; j++) {
493
494 for (i = 0; i < na; i++) {
495 vid = sys->index_anchors[i];
496 EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
497 EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
498 EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
499 }
500 if (!EIG_linear_solver_solve(sys->context)) {
501 sys->has_solution = false;
502 break;
503 }
504 }
505 if (sys->has_solution) {
506 for (vid = 0; vid < sys->verts_num; vid++) {
507 vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
508 vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
509 vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
510 }
511 }
512 else {
513 sys->has_solution = false;
514 }
515 }
516 else {
517 sys->has_solution = false;
518 }
519 }
520}
521
523{
524 int defgrp_index;
525 const MDeformVert *dvert = nullptr;
526
527 MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
528
529 return (dvert != nullptr);
530}
531
532static void initSystem(
533 LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int verts_num)
534{
535 int i;
536 int defgrp_index;
537 int anchors_num;
538 float wpaint;
539 const MDeformVert *dvert = nullptr;
540 const MDeformVert *dv = nullptr;
541 LaplacianSystem *sys;
542 const bool invert_vgroup = (lmd->flag & MOD_LAPLACIANDEFORM_INVERT_VGROUP) != 0;
543
544 if (isValidVertexGroup(lmd, ob, mesh)) {
545 int *index_anchors = MEM_malloc_arrayN<int>(size_t(verts_num), __func__); /* Over-allocate. */
546
547 STACK_DECLARE(index_anchors);
548
549 STACK_INIT(index_anchors, verts_num);
550
551 MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
552 BLI_assert(dvert != nullptr);
553 dv = dvert;
554 for (i = 0; i < verts_num; i++) {
555 wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
556 BKE_defvert_find_weight(dv, defgrp_index);
557 dv++;
558 if (wpaint > 0.0f) {
559 STACK_PUSH(index_anchors, i);
560 }
561 }
562
563 const blender::Span<blender::int2> edges = mesh->edges();
564 const blender::Span<int> corner_verts = mesh->corner_verts();
565 const blender::Span<blender::int3> corner_tris = mesh->corner_tris();
566
567 anchors_num = STACK_SIZE(index_anchors);
568 lmd->cache_system = initLaplacianSystem(verts_num,
569 edges.size(),
570 corner_tris.size(),
571 anchors_num,
572 lmd->anchor_grp_name,
573 lmd->repeat);
574 sys = (LaplacianSystem *)lmd->cache_system;
575 memcpy(sys->index_anchors, index_anchors, sizeof(int) * anchors_num);
576 memcpy(sys->co, vertexCos, sizeof(float[3]) * verts_num);
577 MEM_freeN(index_anchors);
578 lmd->vertexco = MEM_malloc_arrayN<float>(3 * size_t(verts_num), __func__);
580 memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * verts_num);
581 lmd->verts_num = verts_num;
582
584 mesh->verts_num, corner_tris, corner_verts, &sys->ringf_map, &sys->ringf_indices);
585 createVertRingMap(mesh->verts_num, edges, &sys->ringv_map, &sys->ringv_indices);
586
587 for (i = 0; i < sys->tris_num; i++) {
588 sys->tris[i][0] = corner_verts[corner_tris[i][0]];
589 sys->tris[i][1] = corner_verts[corner_tris[i][1]];
590 sys->tris[i][2] = corner_verts[corner_tris[i][2]];
591 }
592 }
593}
594
596 Object *ob,
597 Mesh *mesh,
598 int verts_num)
599{
600 int i;
601 int defgrp_index;
602 int anchors_num = 0;
603 float wpaint;
604 const MDeformVert *dvert = nullptr;
605 const MDeformVert *dv = nullptr;
607 const bool invert_vgroup = (lmd->flag & MOD_LAPLACIANDEFORM_INVERT_VGROUP) != 0;
608
609 if (sys->verts_num != verts_num) {
611 }
612 if (sys->edges_num != mesh->edges_num) {
614 }
615 if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) {
617 }
618 MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
619 if (!dvert) {
621 }
622 dv = dvert;
623 for (i = 0; i < verts_num; i++) {
624 wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
625 BKE_defvert_find_weight(dv, defgrp_index);
626 dv++;
627 if (wpaint > 0.0f) {
628 anchors_num++;
629 }
630 }
631 if (sys->anchors_num != anchors_num) {
633 }
634
636}
637
639 LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int verts_num)
640{
641 float (*filevertexCos)[3];
642 int sysdif;
643 LaplacianSystem *sys = nullptr;
644 filevertexCos = nullptr;
645 if (!(lmd->flag & MOD_LAPLACIANDEFORM_BIND)) {
646 if (lmd->cache_system) {
647 sys = static_cast<LaplacianSystem *>(lmd->cache_system);
649 lmd->cache_system = nullptr;
650 }
651 lmd->verts_num = 0;
653 return;
654 }
655 if (lmd->cache_system) {
656 sysdif = isSystemDifferent(lmd, ob, mesh, verts_num);
657 sys = static_cast<LaplacianSystem *>(lmd->cache_system);
658 if (sysdif) {
660 filevertexCos = MEM_malloc_arrayN<float[3]>(size_t(verts_num), __func__);
661 memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * verts_num);
663 lmd->verts_num = 0;
665 lmd->cache_system = nullptr;
666 initSystem(lmd, ob, mesh, filevertexCos, verts_num);
667 sys = static_cast<LaplacianSystem *>(lmd->cache_system); /* may have been reallocated */
668 MEM_SAFE_FREE(filevertexCos);
669 if (sys) {
670 laplacianDeformPreview(sys, vertexCos);
671 }
672 }
673 else {
674 if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) {
676 ob, &lmd->modifier, "Vertices changed from %d to %d", lmd->verts_num, verts_num);
677 }
678 else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
680 ob, &lmd->modifier, "Edges changed from %d to %d", sys->edges_num, mesh->edges_num);
681 }
682 else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
684 &lmd->modifier,
685 "Vertex group '%s' is not valid, or maybe empty",
686 sys->anchor_grp_name);
687 }
688 }
689 }
690 else {
691 sys->repeat = lmd->repeat;
692 laplacianDeformPreview(sys, vertexCos);
693 }
694 }
695 else {
696 if (!isValidVertexGroup(lmd, ob, mesh)) {
698 &lmd->modifier,
699 "Vertex group '%s' is not valid, or maybe empty",
700 lmd->anchor_grp_name);
702 }
703 else if (lmd->verts_num > 0 && lmd->verts_num == verts_num) {
704 filevertexCos = MEM_malloc_arrayN<float[3]>(size_t(verts_num), "TempDeformCoordinates");
705 memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * verts_num);
707 lmd->verts_num = 0;
708 initSystem(lmd, ob, mesh, filevertexCos, verts_num);
709 sys = static_cast<LaplacianSystem *>(lmd->cache_system);
710 MEM_SAFE_FREE(filevertexCos);
711 laplacianDeformPreview(sys, vertexCos);
712 }
713 else {
714 initSystem(lmd, ob, mesh, vertexCos, verts_num);
715 sys = static_cast<LaplacianSystem *>(lmd->cache_system);
716 laplacianDeformPreview(sys, vertexCos);
717 }
718 }
719 if (sys && sys->is_matrix_computed && !sys->has_solution) {
720 BKE_modifier_set_error(ob, &lmd->modifier, "The system did not find a solution");
721 }
722}
723
732
733static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
734{
737
739
742 tlmd->cache_system = nullptr;
743}
744
745static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
746{
748 if (lmd->anchor_grp_name[0]) {
749 return false;
750 }
751 return true;
752}
753
754static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
755{
757
758 if (lmd->anchor_grp_name[0] != '\0') {
759 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
760 }
761}
762
764 const ModifierEvalContext *ctx,
765 Mesh *mesh,
767{
769 ctx->object,
770 mesh,
771 reinterpret_cast<float (*)[3]>(positions.data()),
772 positions.size());
773}
774
785
786static void panel_draw(const bContext * /*C*/, Panel *panel)
787{
788 uiLayout *row;
789 uiLayout *layout = panel->layout;
790
791 PointerRNA ob_ptr;
793
794 bool is_bind = RNA_boolean_get(ptr, "is_bind");
795 bool has_vertex_group = RNA_string_length(ptr, "vertex_group") != 0;
796
797 layout->use_property_split_set(true);
798
799 layout->prop(ptr, "iterations", UI_ITEM_NONE, std::nullopt, ICON_NONE);
800
801 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
802
803 layout->separator();
804
805 row = &layout->row(true);
806 row->enabled_set(has_vertex_group);
807 row->op(
808 "OBJECT_OT_laplaciandeform_bind", is_bind ? IFACE_("Unbind") : IFACE_("Bind"), ICON_NONE);
809
811}
812
813static void panel_register(ARegionType *region_type)
814{
816}
817
818static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
819{
821 const bool is_undo = BLO_write_is_undo(writer);
822
823 if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
824 BLI_assert(!ID_IS_LINKED(id_owner));
825 const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
826 if (!is_local) {
827 /* Modifier coming from linked data cannot be bound from an override, so we can remove all
828 * binding data, can save a significant amount of memory. */
829 lmd.verts_num = 0;
830 lmd.vertexco = nullptr;
831 lmd.vertexco_sharing_info = nullptr;
832 }
833 }
834
835 if (lmd.vertexco != nullptr) {
837 writer, lmd.vertexco, sizeof(float[3]) * lmd.verts_num, lmd.vertexco_sharing_info, [&]() {
838 BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
839 });
840 }
841
843}
844
845static void blend_read(BlendDataReader *reader, ModifierData *md)
846{
848
849 if (lmd->vertexco) {
850 lmd->vertexco_sharing_info = BLO_read_shared(reader, &lmd->vertexco, [&]() {
851 BLO_read_float3_array(reader, lmd->verts_num, &lmd->vertexco);
852 return blender::implicit_sharing::info_for_mem_free(lmd->vertexco);
853 });
854 }
855 lmd->cache_system = nullptr;
856}
857
859 /*idname*/ "LaplacianDeform",
860 /*name*/ N_("LaplacianDeform"),
861 /*struct_name*/ "LaplacianDeformModifierData",
862 /*struct_size*/ sizeof(LaplacianDeformModifierData),
863 /*srna*/ &RNA_LaplacianDeformModifier,
866 /*icon*/ ICON_MOD_MESHDEFORM,
867 /*copy_data*/ copy_data,
868
869 /*deform_verts*/ deform_verts,
870 /*deform_matrices*/ nullptr,
871 /*deform_verts_EM*/ nullptr,
872 /*deform_matrices_EM*/ nullptr,
873 /*modify_mesh*/ nullptr,
874 /*modify_geometry_set*/ nullptr,
875
876 /*init_data*/ init_data,
877 /*required_data_mask*/ required_data_mask,
878 /*free_data*/ free_data,
879 /*is_disabled*/ is_disabled,
880 /*update_depsgraph*/ nullptr,
881 /*depends_on_time*/ nullptr,
882 /*depends_on_normals*/ nullptr,
883 /*foreach_ID_link*/ nullptr,
884 /*foreach_tex_link*/ nullptr,
885 /*free_runtime_data*/ nullptr,
886 /*panel_register*/ panel_register,
887 /*blend_write*/ blend_write,
888 /*blend_read*/ blend_read,
889 /*foreach_cache*/ nullptr,
890 /*foreach_working_space_color*/ nullptr,
891};
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
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:198
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:41
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
bool BLO_write_is_undo(BlendWriter *writer)
void BLO_write_shared(BlendWriter *writer, const void *data, size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef< void()> write_fn)
const blender::ImplicitSharingInfo * BLO_read_shared(BlendDataReader *reader, T **data_ptr, blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define IFACE_(msgid)
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
@ eModifierFlag_OverrideLibrary_Local
@ eModifierType_LaplacianDeform
@ MOD_LAPLACIANDEFORM_BIND
@ MOD_LAPLACIANDEFORM_INVERT_VGROUP
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 blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void free_data(ModifierData *md)
Definition MOD_bevel.cc:272
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
Definition MOD_bevel.cc:433
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static LaplacianSystem * newLaplacianSystem()
ModifierTypeInfo modifierType_LaplacianDeform
static void laplacianDeformPreview(LaplacianSystem *sys, float(*vertexCos)[3])
static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh)
static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, int verts_num)
static void deleteLaplacianSystem(LaplacianSystem *sys)
static void panel_register(ARegionType *region_type)
static void initLaplacianMatrix(LaplacianSystem *sys)
static LaplacianSystem * initLaplacianSystem(int verts_num, int edges_num, int tris_num, int anchors_num, const char defgrpName[64], int iterations)
static void free_data(ModifierData *md)
static void blend_read(BlendDataReader *reader, ModifierData *md)
@ LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP
@ LAPDEFORM_SYSTEM_IS_DIFFERENT
@ LAPDEFORM_SYSTEM_ONLY_CHANGE_MESH
@ LAPDEFORM_SYSTEM_CHANGE_EDGES
@ LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP
@ LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS
@ LAPDEFORM_SYSTEM_CHANGE_VERTEXES
@ LAPDEFORM_SYSTEM_NOT_CHANGE
static void createVertRingMap(const int mvert_tot, const blender::Span< blender::int2 > edges, MeshElemMap **r_map, int **r_indices)
static void computeImplictRotations(LaplacianSystem *sys)
static void panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float(*vertexCos)[3], int verts_num)
static void rotateDifferentialCoordinates(LaplacianSystem *sys)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void LaplacianDeformModifier_do(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float(*vertexCos)[3], int verts_num)
static void createFaceRingMap(const int mvert_tot, blender::Span< blender::int3 > corner_tris, blender::Span< int > corner_verts, MeshElemMap **r_map, int **r_indices)
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
#define UI_ITEM_NONE
ATTR_WARN_UNUSED_RESULT const BMVert * v2
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T * data() const
Definition BLI_span.hh:539
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
nullptr float
static ushort indices[]
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
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float beta(const float x, const float y)
Definition math_base.h:661
void copy_shared_pointer(T *src_ptr, const ImplicitSharingInfo *src_sharing_info, T **r_dst_ptr, const ImplicitSharingInfo **r_dst_sharing_info)
const ImplicitSharingInfo * info_for_mem_free(void *data)
void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
VecBase< int32_t, 3 > int3
#define fabsf
int RNA_string_length(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:414
const ImplicitSharingInfoHandle * vertexco_sharing_info
LinearSolver * context
int edges_num
int verts_num
struct uiLayout * layout
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void enabled_set(bool enabled)
uiLayout & row(bool align)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
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