Blender V5.0
meshlaplacian.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
9
10#include "MEM_guardedalloc.h"
11
12#include "DNA_mesh_types.h"
13#include "DNA_object_types.h"
14
15#include "BLI_map.hh"
16#include "BLI_math_geom.h"
17#include "BLI_math_matrix.h"
18#include "BLI_math_rotation.h"
19#include "BLI_math_vector.h"
20#include "BLI_memarena.h"
21#include "BLI_ordered_edge.hh"
22#include "BLI_string_utf8.h"
23
24#include "BLT_translation.hh"
25
26#include "BKE_attribute.hh"
27#include "BKE_bvhutils.hh"
28#include "BKE_mesh.hh"
29#include "BKE_mesh_wrapper.hh"
30#include "BKE_modifier.hh"
31
32#include "ED_armature.hh"
33#include "ED_mesh.hh"
34#include "ED_object_vgroup.hh"
35
36#include "eigen_capi.h"
37
38#include "meshlaplacian.h"
39
40#include <algorithm>
41
42/* ************* XXX *************** */
43static void waitcursor(int /*val*/) {}
44static void progress_bar(int /*dummy_val*/, const char * /*dummy*/) {}
45static void start_progress_bar() {}
46static void end_progress_bar() {}
47static void error(const char *str)
48{
49 printf("error: %s\n", str);
50}
51/* ************* XXX *************** */
52
53/************************** Laplacian System *****************************/
54
56 LinearSolver *context; /* linear solver */
57
59
60 float **verts; /* vertex coordinates */
61 float *varea; /* vertex weights for laplacian computation */
62 char *vpinned; /* vertex pinning */
63 int (*faces)[3]; /* face vertex indices */
64 float (*fweights)[3]; /* cotangent weights per face */
65
66 int areaweights; /* use area in cotangent weights? */
67 int storeweights; /* store cotangent weights in fweights */
68 bool variablesdone; /* variables set in linear system */
69
70 blender::Map<blender::OrderedEdge, int> edgehash; /* edge hash for construction */
71
74 blender::Span<int> corner_verts; /* needed to find vertices by index */
77 float (*verts)[3]; /* vertex coordinates */
78 float (*vert_normals)[3]; /* vertex normals */
79
80 float (*root)[3]; /* bone root */
81 float (*tip)[3]; /* bone tip */
83
84 float *H; /* diagonal H matrix */
85 float *p; /* values from all p vectors */
86 float *mindist; /* minimum distance to a bone for all vertices */
87
88 BVHTree *bvhtree; /* ray tracing acceleration structure */
89 const blender::int3 **vltree; /* a corner_tri that the vertex belongs to */
91};
92
93/* Laplacian matrix construction */
94
95/* Computation of these weights for the laplacian is based on:
96 * "Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
97 * Meyer et al, 2002. Section 3.5, formula (8).
98 *
99 * We do it a bit different by going over faces instead of going over each
100 * vertex and adjacent faces, since we don't store this adjacency. Also, the
101 * formulas are tweaked a bit to work for non-manifold meshes. */
102
104 int v1,
105 int v2)
106{
107 edgehash.add_or_modify({v1, v2}, [](int *value) { *value = 1; }, [](int *value) { (*value)++; });
108}
109
111 int v1,
112 int v2)
113{
114 return edgehash.lookup({v1, v2});
115}
116
117static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
118{
119 float t1, t2, t3, len1, len2, len3, area;
120 float *varea = sys->varea, *v1, *v2, *v3;
121 int obtuse = 0;
122
123 v1 = sys->verts[i1];
124 v2 = sys->verts[i2];
125 v3 = sys->verts[i3];
126
127 t1 = cotangent_tri_weight_v3(v1, v2, v3);
128 t2 = cotangent_tri_weight_v3(v2, v3, v1);
129 t3 = cotangent_tri_weight_v3(v3, v1, v2);
130
131 if (angle_v3v3v3(v2, v1, v3) > DEG2RADF(90.0f)) {
132 obtuse = 1;
133 }
134 else if (angle_v3v3v3(v1, v2, v3) > DEG2RADF(90.0f)) {
135 obtuse = 2;
136 }
137 else if (angle_v3v3v3(v1, v3, v2) > DEG2RADF(90.0f)) {
138 obtuse = 3;
139 }
140
141 if (obtuse > 0) {
142 area = area_tri_v3(v1, v2, v3);
143
144 varea[i1] += (obtuse == 1) ? area : area * 0.5f;
145 varea[i2] += (obtuse == 2) ? area : area * 0.5f;
146 varea[i3] += (obtuse == 3) ? area : area * 0.5f;
147 }
148 else {
149 len1 = len_v3v3(v2, v3);
150 len2 = len_v3v3(v1, v3);
151 len3 = len_v3v3(v1, v2);
152
153 t1 *= len1 * len1;
154 t2 *= len2 * len2;
155 t3 *= len3 * len3;
156
157 varea[i1] += (t2 + t3) * 0.25f;
158 varea[i2] += (t1 + t3) * 0.25f;
159 varea[i3] += (t1 + t2) * 0.25f;
160 }
161}
162
163static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
164{
165 float t1, t2, t3;
166 float *varea = sys->varea, *v1, *v2, *v3;
167
168 v1 = sys->verts[i1];
169 v2 = sys->verts[i2];
170 v3 = sys->verts[i3];
171
172 /* instead of *0.5 we divided by the number of faces of the edge, it still
173 * needs to be verified that this is indeed the correct thing to do! */
174 t1 = cotangent_tri_weight_v3(v1, v2, v3) / laplacian_edge_count(sys->edgehash, i2, i3);
175 t2 = cotangent_tri_weight_v3(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1);
176 t3 = cotangent_tri_weight_v3(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2);
177
178 EIG_linear_solver_matrix_add(sys->context, i1, i1, (t2 + t3) * varea[i1]);
179 EIG_linear_solver_matrix_add(sys->context, i2, i2, (t1 + t3) * varea[i2]);
180 EIG_linear_solver_matrix_add(sys->context, i3, i3, (t1 + t2) * varea[i3]);
181
182 EIG_linear_solver_matrix_add(sys->context, i1, i2, -t3 * varea[i1]);
183 EIG_linear_solver_matrix_add(sys->context, i2, i1, -t3 * varea[i2]);
184
185 EIG_linear_solver_matrix_add(sys->context, i2, i3, -t1 * varea[i2]);
186 EIG_linear_solver_matrix_add(sys->context, i3, i2, -t1 * varea[i3]);
187
188 EIG_linear_solver_matrix_add(sys->context, i3, i1, -t2 * varea[i3]);
189 EIG_linear_solver_matrix_add(sys->context, i1, i3, -t2 * varea[i1]);
190
191 if (sys->storeweights) {
192 sys->fweights[f][0] = t1 * varea[i1];
193 sys->fweights[f][1] = t2 * varea[i2];
194 sys->fweights[f][2] = t3 * varea[i3];
195 }
196}
197
198static LaplacianSystem *laplacian_system_construct_begin(int verts_num, int faces_num, int lsq)
199{
200 LaplacianSystem *sys;
201
202 sys = MEM_new<LaplacianSystem>(__func__);
203
204 sys->verts = MEM_calloc_arrayN<float *>(verts_num, "LaplacianSystemVerts");
205 sys->vpinned = MEM_calloc_arrayN<char>(verts_num, "LaplacianSystemVpinned");
206 sys->faces = static_cast<int (*)[3]>(
207 MEM_callocN(sizeof(int[3]) * faces_num, "LaplacianSystemFaces"));
208
209 sys->verts_num = 0;
210 sys->faces_num = 0;
211
212 sys->areaweights = 1;
213 sys->storeweights = 0;
214
215 /* create linear solver */
216 if (lsq) {
217 sys->context = EIG_linear_least_squares_solver_new(0, verts_num, 1);
218 }
219 else {
220 sys->context = EIG_linear_solver_new(0, verts_num, 1);
221 }
222
223 return sys;
224}
225
226void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned)
227{
228 sys->verts[sys->verts_num] = co;
229 sys->vpinned[sys->verts_num] = pinned;
230 sys->verts_num++;
231}
232
233void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3)
234{
235 sys->faces[sys->faces_num][0] = v1;
236 sys->faces[sys->faces_num][1] = v2;
237 sys->faces[sys->faces_num][2] = v3;
238 sys->faces_num++;
239}
240
242{
243 int (*face)[3];
244 int a, verts_num = sys->verts_num, faces_num = sys->faces_num;
245
246 laplacian_begin_solve(sys, 0);
247
248 sys->varea = MEM_calloc_arrayN<float>(verts_num, "LaplacianSystemVarea");
249
250 sys->edgehash.reserve(sys->faces_num);
251 for (a = 0, face = sys->faces; a < sys->faces_num; a++, face++) {
252 laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
253 laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
254 laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
255 }
256
257 if (sys->areaweights) {
258 for (a = 0, face = sys->faces; a < sys->faces_num; a++, face++) {
259 laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
260 }
261 }
262
263 for (a = 0; a < verts_num; a++) {
264 if (sys->areaweights) {
265 if (sys->varea[a] != 0.0f) {
266 sys->varea[a] = 0.5f / sys->varea[a];
267 }
268 }
269 else {
270 sys->varea[a] = 1.0f;
271 }
272
273 /* for heat weighting */
274 if (sys->heat.H) {
275 EIG_linear_solver_matrix_add(sys->context, a, a, sys->heat.H[a]);
276 }
277 }
278
279 if (sys->storeweights) {
280 sys->fweights = static_cast<float (*)[3]>(
281 MEM_callocN(sizeof(float[3]) * faces_num, "LaplacianFWeight"));
282 }
283
284 for (a = 0, face = sys->faces; a < faces_num; a++, face++) {
285 laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);
286 }
287
288 MEM_freeN(sys->faces);
289 sys->faces = nullptr;
290
291 MEM_SAFE_FREE(sys->varea);
292}
293
295{
296 if (sys->verts) {
297 MEM_freeN(sys->verts);
298 }
299 if (sys->varea) {
300 MEM_freeN(sys->varea);
301 }
302 if (sys->vpinned) {
303 MEM_freeN(sys->vpinned);
304 }
305 if (sys->faces) {
306 MEM_freeN(sys->faces);
307 }
308 if (sys->fweights) {
309 MEM_freeN(sys->fweights);
310 }
311
313 MEM_delete(sys);
314}
315
317{
318 int a;
319
320 if (!sys->variablesdone) {
321 if (index >= 0) {
322 for (a = 0; a < sys->verts_num; a++) {
323 if (sys->vpinned[a]) {
324 EIG_linear_solver_variable_set(sys->context, 0, a, sys->verts[a][index]);
326 }
327 }
328 }
329
330 sys->variablesdone = true;
331 }
332}
333
335{
337}
338
340{
341 sys->variablesdone = false;
342
343 // EIG_linear_solver_print_matrix(sys->context, );
344
345 return EIG_linear_solver_solve(sys->context);
346}
347
352
353/************************* Heat Bone Weighting ******************************/
354/* From "Automatic Rigging and Animation of 3D Characters"
355 * Ilya Baran and Jovan Popovic, SIGGRAPH 2007 */
356
357#define C_WEIGHT 1.0f
358#define WEIGHT_LIMIT_START 0.05f
359#define WEIGHT_LIMIT_END 0.025f
360#define DISTANCE_EPSILON 1e-4f
361
363 float start[3];
364 float vec[3];
366};
367
368static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
369{
370 BVHCallbackUserData *data = static_cast<BVHCallbackUserData *>(userdata);
371 const blender::int3 &tri = data->sys->heat.corner_tris[index];
372 const blender::Span<int> corner_verts = data->sys->heat.corner_verts;
373 float (*verts)[3] = data->sys->heat.verts;
374 const float *vtri_co[3];
375 float dist_test;
376
377 vtri_co[0] = verts[corner_verts[tri[0]]];
378 vtri_co[1] = verts[corner_verts[tri[1]]];
379 vtri_co[2] = verts[corner_verts[tri[2]]];
380
381#ifdef USE_KDOPBVH_WATERTIGHT
383 data->start, ray->isect_precalc, UNPACK3(vtri_co), &dist_test, nullptr))
384#else
385 UNUSED_VARS(ray);
386 if (isect_ray_tri_v3(data->start, data->vec, UNPACK3(vtri_co), &dist_test, nullptr))
387#endif
388 {
389 if (dist_test < hit->dist) {
390 float n[3];
391 normal_tri_v3(n, UNPACK3(vtri_co));
392 if (dot_v3v3(n, data->vec) < -1e-5f) {
393 hit->index = index;
394 hit->dist = dist_test;
395 }
396 }
397 }
398}
399
400/* Ray-tracing for vertex to bone/vertex visibility. */
402{
403 const blender::int3 *corner_tris = sys->heat.corner_tris;
404 const blender::Span<int> corner_verts = sys->heat.corner_verts;
405 float (*verts)[3] = sys->heat.verts;
406 int tris_num = sys->heat.tris_num;
407 int verts_num = sys->heat.verts_num;
408 int a;
409
410 sys->heat.bvhtree = BLI_bvhtree_new(tris_num, 0.0f, 4, 6);
411 sys->heat.vltree = static_cast<const blender::int3 **>(
412 MEM_callocN(sizeof(blender::int3 *) * verts_num, "HeatVFaces"));
413
414 for (a = 0; a < tris_num; a++) {
415 const blender::int3 &tri = corner_tris[a];
416 float bb[6];
417 int vtri[3];
418
419 vtri[0] = corner_verts[tri[0]];
420 vtri[1] = corner_verts[tri[1]];
421 vtri[2] = corner_verts[tri[2]];
422
423 INIT_MINMAX(bb, bb + 3);
424 minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]);
425 minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]);
426 minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]);
427
428 BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
429
430 /* Setup inverse pointers to use on isect.orig */
431 sys->heat.vltree[vtri[0]] = &tri;
432 sys->heat.vltree[vtri[1]] = &tri;
433 sys->heat.vltree[vtri[2]] = &tri;
434 }
435
437}
438
439static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
440{
441 BVHTreeRayHit hit;
443 const blender::int3 *lt;
444 float end[3];
445 int visible;
446
447 lt = sys->heat.vltree[vertex];
448 if (lt == nullptr) {
449 return 1;
450 }
451
452 data.sys = sys;
453 copy_v3_v3(data.start, sys->heat.verts[vertex]);
454
455 closest_to_line_segment_v3(end, data.start, sys->heat.root[source], sys->heat.tip[source]);
456
457 sub_v3_v3v3(data.vec, end, data.start);
458 madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
459 mul_v3_fl(data.vec, 1.0f - 2e-5f);
460
461 /* pass normalized vec + distance to bvh */
462 hit.index = -1;
463 hit.dist = normalize_v3(data.vec);
464
465 visible =
467 sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void *)&data) == -1;
468
469 return visible;
470}
471
472static float heat_source_distance(LaplacianSystem *sys, int vertex, int source)
473{
474 float closest[3], d[3], dist, cosine;
475
476 /* compute Euclidean distance */
478 closest, sys->heat.verts[vertex], sys->heat.root[source], sys->heat.tip[source]);
479
480 sub_v3_v3v3(d, sys->heat.verts[vertex], closest);
481 dist = normalize_v3(d);
482
483 /* if the vertex normal does not point along the bone, increase distance */
484 cosine = dot_v3v3(d, sys->heat.vert_normals[vertex]);
485
486 return dist / (0.5f * (cosine + 1.001f));
487}
488
489static int heat_source_closest(LaplacianSystem *sys, int vertex, int source)
490{
491 float dist;
492
493 dist = heat_source_distance(sys, vertex, source);
494
495 if (dist <= sys->heat.mindist[vertex] * (1.0f + DISTANCE_EPSILON)) {
496 if (heat_ray_source_visible(sys, vertex, source)) {
497 return 1;
498 }
499 }
500
501 return 0;
502}
503
504static void heat_set_H(LaplacianSystem *sys, int vertex)
505{
506 float dist, mindist, h;
507 int j, numclosest = 0;
508
509 mindist = 1e10;
510
511 /* compute minimum distance */
512 for (j = 0; j < sys->heat.numsource; j++) {
513 dist = heat_source_distance(sys, vertex, j);
514
515 mindist = std::min(dist, mindist);
516 }
517
518 sys->heat.mindist[vertex] = mindist;
519
520 /* count number of sources with approximately this minimum distance */
521 for (j = 0; j < sys->heat.numsource; j++) {
522 if (heat_source_closest(sys, vertex, j)) {
523 numclosest++;
524 }
525 }
526
527 sys->heat.p[vertex] = (numclosest > 0) ? 1.0f / numclosest : 0.0f;
528
529 /* compute H entry */
530 if (numclosest > 0) {
531 mindist = max_ff(mindist, 1e-4f);
532 h = numclosest * C_WEIGHT / (mindist * mindist);
533 }
534 else {
535 h = 0.0f;
536 }
537
538 sys->heat.H[vertex] = h;
539}
540
542{
543 float fnor[3];
544 int a, v1, v2, v3, (*face)[3];
545
546 sys->heat.vert_normals = static_cast<float (*)[3]>(
547 MEM_callocN(sizeof(float[3]) * sys->verts_num, "HeatVNors"));
548
549 for (a = 0, face = sys->faces; a < sys->faces_num; a++, face++) {
550 v1 = (*face)[0];
551 v2 = (*face)[1];
552 v3 = (*face)[2];
553
554 normal_tri_v3(fnor, sys->verts[v1], sys->verts[v2], sys->verts[v3]);
555
556 add_v3_v3(sys->heat.vert_normals[v1], fnor);
557 add_v3_v3(sys->heat.vert_normals[v2], fnor);
558 add_v3_v3(sys->heat.vert_normals[v3], fnor);
559 }
560
561 for (a = 0; a < sys->verts_num; a++) {
563 }
564}
565
567{
568 const blender::int3 *corner_tris = sys->heat.corner_tris;
569 const blender::Span<int> corner_verts = sys->heat.corner_verts;
570 int tris_num = sys->heat.tris_num;
571 int verts_num = sys->heat.verts_num;
572 int a;
573
574 /* heat specific definitions */
575 sys->heat.mindist = MEM_calloc_arrayN<float>(verts_num, "HeatMinDist");
576 sys->heat.H = MEM_calloc_arrayN<float>(verts_num, "HeatH");
577 sys->heat.p = MEM_calloc_arrayN<float>(verts_num, "HeatP");
578
579 /* add verts and faces to laplacian */
580 for (a = 0; a < verts_num; a++) {
581 laplacian_add_vertex(sys, sys->heat.verts[a], 0);
582 }
583
584 for (a = 0; a < tris_num; a++) {
585 int vtri[3];
586 vtri[0] = corner_verts[corner_tris[a][0]];
587 vtri[1] = corner_verts[corner_tris[a][1]];
588 vtri[2] = corner_verts[corner_tris[a][2]];
590 }
591
592 /* for distance computation in set_H */
594
595 for (a = 0; a < verts_num; a++) {
596 heat_set_H(sys, a);
597 }
598}
599
601{
603 MEM_freeN(sys->heat.vltree);
605
606 MEM_freeN(sys->heat.mindist);
607 MEM_freeN(sys->heat.H);
608 MEM_freeN(sys->heat.p);
610}
611
612static float heat_limit_weight(float weight)
613{
614 float t;
615
616 if (weight < WEIGHT_LIMIT_END) {
617 return 0.0f;
618 }
619 if (weight < WEIGHT_LIMIT_START) {
621 return t * WEIGHT_LIMIT_START;
622 }
623 return weight;
624}
625
627 Mesh *mesh,
628 float (*verts)[3],
629 int numbones,
630 bDeformGroup **dgrouplist,
631 bDeformGroup **dgroupflip,
632 float (*root)[3],
633 float (*tip)[3],
634 const bool *selected,
635 const char **r_error_str)
636{
637 using namespace blender;
638 LaplacianSystem *sys;
639 blender::int3 *corner_tris;
640 float solution, weight;
641 int *vertsflipped = nullptr, *mask = nullptr;
642 int a, tris_num, j, bbone, firstsegment, lastsegment;
643 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
644
645 const blender::Span<blender::float3> vert_positions = mesh->vert_positions();
646 const blender::OffsetIndices faces = mesh->faces();
647 const blender::Span<int> corner_verts = mesh->corner_verts();
648 const bke::AttributeAccessor attributes = mesh->attributes();
649 bool use_vert_sel = (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
650 bool use_face_sel = (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
651
652 *r_error_str = nullptr;
653
654 /* bone heat needs triangulated faces */
655 tris_num = poly_to_tri_count(mesh->faces_num, mesh->corners_num);
656
657 /* count triangles and create mask */
658 if (ob->mode & OB_MODE_WEIGHT_PAINT && (use_face_sel || use_vert_sel)) {
659 mask = MEM_calloc_arrayN<int>(mesh->verts_num, "heat_bone_weighting mask");
660
661 /* (added selectedVerts content for vertex mask, they used to just equal 1) */
662 if (use_vert_sel) {
663 const VArray select_vert = *attributes.lookup_or_default<bool>(
664 ".select_vert", bke::AttrDomain::Point, false);
665 if (select_vert) {
666 for (const int i : faces.index_range()) {
667 for (const int vert : corner_verts.slice(faces[i])) {
668 mask[vert] = select_vert[vert];
669 }
670 }
671 }
672 }
673 else if (use_face_sel) {
674 const VArray select_poly = *attributes.lookup_or_default<bool>(
675 ".select_poly", bke::AttrDomain::Face, false);
676 if (select_poly) {
677 for (const int i : faces.index_range()) {
678 if (select_poly[i]) {
679 for (const int vert : corner_verts.slice(faces[i])) {
680 mask[vert] = 1;
681 }
682 }
683 }
684 }
685 }
686 }
687
688 /* create laplacian */
689 sys = laplacian_system_construct_begin(mesh->verts_num, tris_num, 1);
690
692 corner_tris = static_cast<blender::int3 *>(
693 MEM_mallocN(sizeof(*sys->heat.corner_tris) * sys->heat.tris_num, __func__));
694
696 vert_positions, faces, corner_verts, {corner_tris, sys->heat.tris_num});
697
698 sys->heat.corner_tris = corner_tris;
699 sys->heat.corner_verts = corner_verts;
700 sys->heat.verts_num = mesh->verts_num;
701 sys->heat.verts = verts;
702 sys->heat.root = root;
703 sys->heat.tip = tip;
704 sys->heat.numsource = numbones;
705
708
710
711 if (dgroupflip) {
712 vertsflipped = MEM_calloc_arrayN<int>(mesh->verts_num, "vertsflipped");
713 for (a = 0; a < mesh->verts_num; a++) {
714 vertsflipped[a] = mesh_get_x_mirror_vert(ob, nullptr, a, use_topology);
715 }
716 }
717
718 /* compute weights per bone */
719 for (j = 0; j < numbones; j++) {
720 if (selected[j] == false) {
721 continue;
722 }
723
724 firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]);
725 lastsegment = (j == numbones - 1 || dgrouplist[j] != dgrouplist[j + 1]);
726 bbone = !(firstsegment && lastsegment);
727
728 /* clear weights */
729 if (bbone && firstsegment) {
730 for (a = 0; a < mesh->verts_num; a++) {
731 if (mask && !mask[a]) {
732 continue;
733 }
734
735 blender::ed::object::vgroup_vert_remove(ob, dgrouplist[j], a);
736 if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
737 blender::ed::object::vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
738 }
739 }
740 }
741
742 /* fill right hand side */
743 laplacian_begin_solve(sys, -1);
744
745 for (a = 0; a < mesh->verts_num; a++) {
746 if (heat_source_closest(sys, a, j)) {
747 laplacian_add_right_hand_side(sys, a, sys->heat.H[a] * sys->heat.p[a]);
748 }
749 }
750
751 /* solve */
752 if (laplacian_system_solve(sys)) {
753 /* load solution into vertex groups */
754 for (a = 0; a < mesh->verts_num; a++) {
755 if (mask && !mask[a]) {
756 continue;
757 }
758
759 solution = laplacian_system_get_solution(sys, a);
760
761 if (bbone) {
762 if (solution > 0.0f) {
763 blender::ed::object::vgroup_vert_add(ob, dgrouplist[j], a, solution, WEIGHT_ADD);
764 }
765 }
766 else {
767 weight = heat_limit_weight(solution);
768 if (weight > 0.0f) {
769 blender::ed::object::vgroup_vert_add(ob, dgrouplist[j], a, weight, WEIGHT_REPLACE);
770 }
771 else {
772 blender::ed::object::vgroup_vert_remove(ob, dgrouplist[j], a);
773 }
774 }
775
776 /* do same for mirror */
777 if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
778 if (bbone) {
779 if (solution > 0.0f) {
781 ob, dgroupflip[j], vertsflipped[a], solution, WEIGHT_ADD);
782 }
783 }
784 else {
785 weight = heat_limit_weight(solution);
786 if (weight > 0.0f) {
788 ob, dgroupflip[j], vertsflipped[a], weight, WEIGHT_REPLACE);
789 }
790 else {
791 blender::ed::object::vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
792 }
793 }
794 }
795 }
796 }
797 else if (*r_error_str == nullptr) {
798 *r_error_str = N_("Bone Heat Weighting: failed to find solution for one or more bones");
799 break;
800 }
801
802 /* remove too small vertex weights */
803 if (bbone && lastsegment) {
804 for (a = 0; a < mesh->verts_num; a++) {
805 if (mask && !mask[a]) {
806 continue;
807 }
808
809 weight = blender::ed::object::vgroup_vert_weight(ob, dgrouplist[j], a);
810 weight = heat_limit_weight(weight);
811 if (weight <= 0.0f) {
812 blender::ed::object::vgroup_vert_remove(ob, dgrouplist[j], a);
813 }
814
815 if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
816 weight = blender::ed::object::vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
817 weight = heat_limit_weight(weight);
818 if (weight <= 0.0f) {
819 blender::ed::object::vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
820 }
821 }
822 }
823 }
824 }
825
826 /* free */
827 if (vertsflipped) {
828 MEM_freeN(vertsflipped);
829 }
830 if (mask) {
832 }
833
834 heat_system_free(sys);
835
837}
838
839/************************** Harmonic Coordinates ****************************/
840/* From "Harmonic Coordinates for Character Articulation",
841 * Pushkar Joshi, Mark Meyer, Tony DeRose, Brian Green and Tom Sanocki,
842 * SIGGRAPH 2007. */
843
844#define EPSILON 0.0001f
845
846#define MESHDEFORM_TAG_UNTYPED 0
847#define MESHDEFORM_TAG_BOUNDARY 1
848#define MESHDEFORM_TAG_INTERIOR 2
849#define MESHDEFORM_TAG_EXTERIOR 3
850
852#define MESHDEFORM_LEN_THRESHOLD 1e-6f
853
854#define MESHDEFORM_MIN_INFLUENCE 0.0005f
855
856static const int MESHDEFORM_OFFSET[7][3] = {
857 {0, 0, 0},
858 {1, 0, 0},
859 {-1, 0, 0},
860 {0, 1, 0},
861 {0, -1, 0},
862 {0, 0, 1},
863 {0, 0, -1},
864};
865
867 /* intersection on the cage 'cagecos' */
868 float co[3];
869 /* non-facing intersections are considered interior */
870 bool facing;
871 /* ray-cast index aligned with polygons (ray-hit-triangle isn't needed) */
873 /* distance from 'co' to the ray-cast start (clamped to avoid zero division) */
874 float len;
875 /* weights aligned with the polygons's loop indices */
876 float poly_weights[0];
877};
878
884
886 /* grid dimensions */
887 float min[3], max[3];
888 float width[3], halfwidth[3];
890
891 /* meshes */
896
897 /* grids */
899 MDefBoundIsect *(*boundisect)[6];
901 int *tag;
902 float *phi, *totalphi;
903
904 /* mesh stuff */
905 int *inside;
906 float *weights;
908 float cagemat[4][4];
909
910 /* direct solver */
911 int *varidx;
912
915
916 /* avoid DM function calls during intersections */
917 struct {
924};
925
927 float start[3];
928 float vec[3];
930 float lambda;
931
932 bool isect;
933 float u, v;
934};
935
936/* ray intersection */
937
942
943static void harmonic_ray_callback(void *userdata,
944 int index,
945 const BVHTreeRay *ray,
946 BVHTreeRayHit *hit)
947{
948 MeshRayCallbackData *data = static_cast<MeshRayCallbackData *>(userdata);
949 MeshDeformBind *mdb = data->mdb;
950 const blender::Span<int> corner_verts = mdb->cagemesh_cache.corner_verts;
951 const blender::Span<int> tri_faces = mdb->cagemesh_cache.tri_faces;
953 MeshDeformIsect *isec = data->isec;
954 float no[3], co[3], dist;
955 float *face[3];
956
957 const blender::int3 &tri = mdb->cagemesh_cache.corner_tris[index];
958
959 face[0] = mdb->cagecos[corner_verts[tri[0]]];
960 face[1] = mdb->cagecos[corner_verts[tri[1]]];
961 face[2] = mdb->cagecos[corner_verts[tri[2]]];
962
963 bool isect_ray_tri = isect_ray_tri_watertight_v3(
964 ray->origin, ray->isect_precalc, UNPACK3(face), &dist, nullptr);
965
966 if (!isect_ray_tri || dist > isec->vec_length) {
967 return;
968 }
969
970 if (!face_normals.is_empty()) {
971 copy_v3_v3(no, face_normals[tri_faces[index]]);
972 }
973 else {
974 normal_tri_v3(no, UNPACK3(face));
975 }
976
977 madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
978 dist /= isec->vec_length;
979 if (dist < hit->dist) {
980 hit->index = index;
981 hit->dist = dist;
982 copy_v3_v3(hit->co, co);
983
984 isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f);
985 isec->lambda = dist;
986 }
987}
988
990 const float co1[3],
991 const float co2[3])
992{
993 BVHTreeRayHit hit;
994 MeshDeformIsect isect_mdef;
996 mdb,
997 &isect_mdef,
998 };
999 float end[3], vec_normal[3];
1000
1001 /* happens binding when a cage has no faces */
1002 if (UNLIKELY(mdb->bvhtree == nullptr)) {
1003 return nullptr;
1004 }
1005
1006 /* setup isec */
1007 memset(&isect_mdef, 0, sizeof(isect_mdef));
1008 isect_mdef.lambda = 1e10f;
1009
1010 copy_v3_v3(isect_mdef.start, co1);
1011 copy_v3_v3(end, co2);
1012 sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
1013 isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);
1014
1015 hit.index = -1;
1018 isect_mdef.start,
1019 vec_normal,
1020 0.0,
1021 &hit,
1023 &data,
1025 {
1026 const blender::Span<int> corner_verts = mdb->cagemesh_cache.corner_verts;
1027 const int face_i = mdb->cagemesh_cache.tri_faces[hit.index];
1028 const blender::IndexRange face = mdb->cagemesh_cache.faces[face_i];
1029 const float (*cagecos)[3] = mdb->cagecos;
1030 const float len = isect_mdef.lambda;
1031 MDefBoundIsect *isect;
1032
1033 blender::Array<blender::float3, 64> mp_cagecos(face.size());
1034
1035 /* create MDefBoundIsect, and extra for 'poly_weights[]' */
1036 isect = static_cast<MDefBoundIsect *>(
1037 BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * face.size())));
1038
1039 /* compute intersection coordinate */
1040 madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);
1041
1042 isect->facing = isect_mdef.isect;
1043
1044 isect->face_index = face_i;
1045
1046 isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);
1047
1048 /* compute mean value coordinates for interpolation */
1049 for (int i = 0; i < face.size(); i++) {
1050 copy_v3_v3(mp_cagecos[i], cagecos[corner_verts[face[i]]]);
1051 }
1052
1054 reinterpret_cast<float (*)[3]>(mp_cagecos.data()),
1055 face.size(),
1056 isect->co);
1057
1058 return isect;
1059 }
1060
1061 return nullptr;
1062}
1063
1064static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
1065{
1066 MDefBoundIsect *isect;
1067 float outside[3], start[3], dir[3];
1068 int i;
1069
1070 for (i = 1; i <= 6; i++) {
1071 outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f) * MESHDEFORM_OFFSET[i][0];
1072 outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f) * MESHDEFORM_OFFSET[i][1];
1073 outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f) * MESHDEFORM_OFFSET[i][2];
1074
1075 copy_v3_v3(start, co);
1076 sub_v3_v3v3(dir, outside, start);
1077 normalize_v3(dir);
1078
1079 isect = meshdeform_ray_tree_intersect(mdb, start, outside);
1080 if (isect && !isect->facing) {
1081 return 1;
1082 }
1083 }
1084
1085 return 0;
1086}
1087
1088/* solving */
1089
1090BLI_INLINE int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
1091{
1092 int size = mdb->size;
1093
1094 x += MESHDEFORM_OFFSET[n][0];
1095 y += MESHDEFORM_OFFSET[n][1];
1096 z += MESHDEFORM_OFFSET[n][2];
1097
1098 if (x < 0 || x >= mdb->size) {
1099 return -1;
1100 }
1101 if (y < 0 || y >= mdb->size) {
1102 return -1;
1103 }
1104 if (z < 0 || z >= mdb->size) {
1105 return -1;
1106 }
1107
1108 return x + y * size + z * size * size;
1109}
1110
1112 MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
1113{
1114 x += MESHDEFORM_OFFSET[n][0];
1115 y += MESHDEFORM_OFFSET[n][1];
1116 z += MESHDEFORM_OFFSET[n][2];
1117
1118 center[0] = mdb->min[0] + x * mdb->width[0] + mdb->halfwidth[0];
1119 center[1] = mdb->min[1] + y * mdb->width[1] + mdb->halfwidth[1];
1120 center[2] = mdb->min[2] + z * mdb->width[2] + mdb->halfwidth[2];
1121}
1122
1123static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z)
1124{
1125 MDefBoundIsect *isect;
1126 float center[3], ncenter[3];
1127 int i, a;
1128
1129 a = meshdeform_index(mdb, x, y, z, 0);
1130 meshdeform_cell_center(mdb, x, y, z, 0, center);
1131
1132 /* check each outgoing edge for intersection */
1133 for (i = 1; i <= 6; i++) {
1134 if (meshdeform_index(mdb, x, y, z, i) == -1) {
1135 continue;
1136 }
1137
1138 meshdeform_cell_center(mdb, x, y, z, i, ncenter);
1139
1140 isect = meshdeform_ray_tree_intersect(mdb, center, ncenter);
1141 if (isect) {
1142 mdb->boundisect[a][i - 1] = isect;
1143 mdb->tag[a] = MESHDEFORM_TAG_BOUNDARY;
1144 }
1145 }
1146}
1147
1149{
1150 int *stack, *tag = mdb->tag;
1151 int a, b, i, xyz[3], stacksize, size = mdb->size;
1152
1153 stack = MEM_calloc_arrayN<int>(mdb->size3, __func__);
1154
1155 /* we know lower left corner is EXTERIOR because of padding */
1156 tag[0] = MESHDEFORM_TAG_EXTERIOR;
1157 stack[0] = 0;
1158 stacksize = 1;
1159
1160 /* floodfill exterior tag */
1161 while (stacksize > 0) {
1162 a = stack[--stacksize];
1163
1164 xyz[2] = a / (size * size);
1165 xyz[1] = (a - xyz[2] * size * size) / size;
1166 xyz[0] = a - xyz[1] * size - xyz[2] * size * size;
1167
1168 for (i = 1; i <= 6; i++) {
1169 b = meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i);
1170
1171 if (b != -1) {
1172 if (tag[b] == MESHDEFORM_TAG_UNTYPED ||
1173 (tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i - 1]))
1174 {
1176 stack[stacksize++] = b;
1177 }
1178 }
1179 }
1180 }
1181
1182 /* other cells are interior */
1183 for (a = 0; a < size * size * size; a++) {
1184 if (tag[a] == MESHDEFORM_TAG_UNTYPED) {
1185 tag[a] = MESHDEFORM_TAG_INTERIOR;
1186 }
1187 }
1188
1189#if 0
1190 {
1191 int tb, ti, te, ts;
1192 tb = ti = te = ts = 0;
1193 for (a = 0; a < size * size * size; a++) {
1194 if (tag[a] == MESHDEFORM_TAG_BOUNDARY) {
1195 tb++;
1196 }
1197 else if (tag[a] == MESHDEFORM_TAG_INTERIOR) {
1198 ti++;
1199 }
1200 else if (tag[a] == MESHDEFORM_TAG_EXTERIOR) {
1201 te++;
1202
1203 if (mdb->semibound[a]) {
1204 ts++;
1205 }
1206 }
1207 }
1208
1209 printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts);
1210 }
1211#endif
1212
1213 MEM_freeN(stack);
1214}
1215
1217 const MDefBoundIsect *isect,
1218 int cagevert)
1219{
1220 const blender::IndexRange face = mdb->cagemesh_cache.faces[isect->face_index];
1221 const blender::Span<int> corner_verts = mdb->cagemesh_cache.corner_verts;
1222
1223 for (int i = 0; i < face.size(); i++) {
1224 if (corner_verts[face[i]] == cagevert) {
1225 return isect->poly_weights[i];
1226 }
1227 }
1228
1229 return 0.0f;
1230}
1231
1233 const float *gridvec,
1234 float * /*vec*/,
1235 int /*cagevert*/)
1236{
1237 float dvec[3], ivec[3], result = 0.0f;
1238 float totweight = 0.0f;
1239
1240 for (int i = 0; i < 3; i++) {
1241 ivec[i] = int(gridvec[i]);
1242 dvec[i] = gridvec[i] - ivec[i];
1243 }
1244
1245 for (int i = 0; i < 8; i++) {
1246 int x, y, z;
1247 float wx, wy, wz;
1248
1249 if (i & 1) {
1250 x = ivec[0] + 1;
1251 wx = dvec[0];
1252 }
1253 else {
1254 x = ivec[0];
1255 wx = 1.0f - dvec[0];
1256 }
1257
1258 if (i & 2) {
1259 y = ivec[1] + 1;
1260 wy = dvec[1];
1261 }
1262 else {
1263 y = ivec[1];
1264 wy = 1.0f - dvec[1];
1265 }
1266
1267 if (i & 4) {
1268 z = ivec[2] + 1;
1269 wz = dvec[2];
1270 }
1271 else {
1272 z = ivec[2];
1273 wz = 1.0f - dvec[2];
1274 }
1275
1276 CLAMP(x, 0, mdb->size - 1);
1277 CLAMP(y, 0, mdb->size - 1);
1278 CLAMP(z, 0, mdb->size - 1);
1279
1280 int a = meshdeform_index(mdb, x, y, z, 0);
1281 float weight = wx * wy * wz;
1282 result += weight * mdb->phi[a];
1283 totweight += weight;
1284 }
1285
1286 if (totweight > 0.0f) {
1287 result /= totweight;
1288 }
1289
1290 return result;
1291}
1292
1293static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z)
1294{
1295 int i, a;
1296
1297 a = meshdeform_index(mdb, x, y, z, 0);
1298 if (mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR) {
1299 return;
1300 }
1301
1302 for (i = 1; i <= 6; i++) {
1303 if (mdb->boundisect[a][i - 1]) {
1304 mdb->semibound[a] = 1;
1305 }
1306 }
1307}
1308
1309static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z)
1310{
1311 float weight, totweight = 0.0f;
1312 int i, a;
1313
1314 a = meshdeform_index(mdb, x, y, z, 0);
1315
1316 /* count weight for neighbor cells */
1317 for (i = 1; i <= 6; i++) {
1318 if (meshdeform_index(mdb, x, y, z, i) == -1) {
1319 continue;
1320 }
1321
1322 if (mdb->boundisect[a][i - 1]) {
1323 weight = 1.0f / mdb->boundisect[a][i - 1]->len;
1324 }
1325 else if (!mdb->semibound[a]) {
1326 weight = 1.0f / mdb->width[0];
1327 }
1328 else {
1329 weight = 0.0f;
1330 }
1331
1332 totweight += weight;
1333 }
1334
1335 return totweight;
1336}
1337
1339 MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z)
1340{
1341 MDefBoundIsect *isect;
1342 float weight, totweight;
1343 int i, a, acenter;
1344
1345 acenter = meshdeform_index(mdb, x, y, z, 0);
1346 if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR) {
1347 return;
1348 }
1349
1350 EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
1351
1352 totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
1353 for (i = 1; i <= 6; i++) {
1354 a = meshdeform_index(mdb, x, y, z, i);
1355 if (a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) {
1356 continue;
1357 }
1358
1359 isect = mdb->boundisect[acenter][i - 1];
1360 if (!isect) {
1361 weight = (1.0f / mdb->width[0]) / totweight;
1362 EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[a], -weight);
1363 }
1364 }
1365}
1366
1368 MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z, int cagevert)
1369{
1370 MDefBoundIsect *isect;
1371 float rhs, weight, totweight;
1372 int i, a, acenter;
1373
1374 acenter = meshdeform_index(mdb, x, y, z, 0);
1375 if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR) {
1376 return;
1377 }
1378
1379 totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
1380 for (i = 1; i <= 6; i++) {
1381 a = meshdeform_index(mdb, x, y, z, i);
1382 if (a == -1) {
1383 continue;
1384 }
1385
1386 isect = mdb->boundisect[acenter][i - 1];
1387
1388 if (isect) {
1389 weight = (1.0f / isect->len) / totweight;
1390 rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
1391 EIG_linear_solver_right_hand_side_add(context, 0, mdb->varidx[acenter], rhs);
1392 }
1393 }
1394}
1395
1397 MeshDeformBind *mdb, int x, int y, int z, int cagevert)
1398{
1399 MDefBoundIsect *isect;
1400 float rhs, weight, totweight;
1401 int i, a;
1402
1403 a = meshdeform_index(mdb, x, y, z, 0);
1404 if (!mdb->semibound[a]) {
1405 return;
1406 }
1407
1408 mdb->phi[a] = 0.0f;
1409
1410 totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
1411 for (i = 1; i <= 6; i++) {
1412 isect = mdb->boundisect[a][i - 1];
1413
1414 if (isect) {
1415 weight = (1.0f / isect->len) / totweight;
1416 rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
1417 mdb->phi[a] += rhs;
1418 }
1419 }
1420}
1421
1423 MeshDeformBind *mdb, int x, int y, int z, int /*cagevert*/)
1424{
1425 float phi, totweight;
1426 int i, a, acenter;
1427
1428 acenter = meshdeform_index(mdb, x, y, z, 0);
1429 if (mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter]) {
1430 return;
1431 }
1432
1433 phi = 0.0f;
1434 totweight = 0.0f;
1435 for (i = 1; i <= 6; i++) {
1436 a = meshdeform_index(mdb, x, y, z, i);
1437
1438 if (a != -1 && mdb->semibound[a]) {
1439 phi += mdb->phi[a];
1440 totweight += 1.0f;
1441 }
1442 }
1443
1444 if (totweight != 0.0f) {
1445 mdb->phi[acenter] = phi / totweight;
1446 }
1447}
1448
1450{
1451 LinearSolver *context;
1452 float vec[3], gridvec[3];
1453 int a, b, x, y, z, totvar;
1454 char message[256];
1455
1456 /* setup variable indices */
1457 mdb->varidx = MEM_calloc_arrayN<int>(mdb->size3, "MeshDeformDSvaridx");
1458 for (a = 0, totvar = 0; a < mdb->size3; a++) {
1459 mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++;
1460 }
1461
1462 if (totvar == 0) {
1463 MEM_freeN(mdb->varidx);
1464 return;
1465 }
1466
1467 progress_bar(0, "Starting mesh deform solve");
1468
1469 /* setup linear solver */
1470 context = EIG_linear_solver_new(totvar, totvar, 1);
1471
1472 /* build matrix */
1473 for (z = 0; z < mdb->size; z++) {
1474 for (y = 0; y < mdb->size; y++) {
1475 for (x = 0; x < mdb->size; x++) {
1476 meshdeform_matrix_add_cell(mdb, context, x, y, z);
1477 }
1478 }
1479 }
1480
1481 /* solve for each cage vert */
1482 for (a = 0; a < mdb->cage_verts_num; a++) {
1483 /* fill in right hand side and solve */
1484 for (z = 0; z < mdb->size; z++) {
1485 for (y = 0; y < mdb->size; y++) {
1486 for (x = 0; x < mdb->size; x++) {
1487 meshdeform_matrix_add_rhs(mdb, context, x, y, z, a);
1488 }
1489 }
1490 }
1491
1492 if (EIG_linear_solver_solve(context)) {
1493 for (z = 0; z < mdb->size; z++) {
1494 for (y = 0; y < mdb->size; y++) {
1495 for (x = 0; x < mdb->size; x++) {
1497 }
1498 }
1499 }
1500
1501 for (z = 0; z < mdb->size; z++) {
1502 for (y = 0; y < mdb->size; y++) {
1503 for (x = 0; x < mdb->size; x++) {
1505 }
1506 }
1507 }
1508
1509 for (b = 0; b < mdb->size3; b++) {
1510 if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) {
1511 mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]);
1512 }
1513 mdb->totalphi[b] += mdb->phi[b];
1514 }
1515
1516 if (mdb->weights) {
1517 /* static bind : compute weights for each vertex */
1518 for (b = 0; b < mdb->verts_num; b++) {
1519 if (mdb->inside[b]) {
1520 copy_v3_v3(vec, mdb->vertexcos[b]);
1521 gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0];
1522 gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1];
1523 gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2];
1524
1525 mdb->weights[b * mdb->cage_verts_num + a] = meshdeform_interp_w(mdb, gridvec, vec, a);
1526 }
1527 }
1528 }
1529 else {
1530 MDefBindInfluence *inf;
1531
1532 /* dynamic bind */
1533 for (b = 0; b < mdb->size3; b++) {
1534 if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) {
1535 inf = static_cast<MDefBindInfluence *>(
1536 BLI_memarena_alloc(mdb->memarena, sizeof(*inf)));
1537 inf->vertex = a;
1538 inf->weight = mdb->phi[b];
1539 inf->next = mdb->dyngrid[b];
1540 mdb->dyngrid[b] = inf;
1541 }
1542 }
1543 }
1544 }
1545 else {
1547 mmd->object, &mmd->modifier, "Failed to find bind solution (increase precision?)");
1548 error("Mesh Deform: failed to find bind solution.");
1549 break;
1550 }
1551
1552 SNPRINTF_UTF8(message, "Mesh deform solve %d / %d |||", a + 1, mdb->cage_verts_num);
1553 progress_bar(float(a + 1) / float(mdb->cage_verts_num), message);
1554 }
1555
1556#if 0
1557 /* sanity check */
1558 for (b = 0; b < mdb->size3; b++) {
1559 if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) {
1560 if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f) {
1561 printf("totalphi deficiency [%s|%d] %d: %.10f\n",
1562 (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary",
1563 mdb->semibound[b],
1564 mdb->varidx[b],
1565 mdb->totalphi[b]);
1566 }
1567 }
1568 }
1569#endif
1570
1571 /* free */
1572 MEM_freeN(mdb->varidx);
1573
1574 EIG_linear_solver_delete(context);
1575}
1576
1578{
1579 using namespace blender;
1580 MDefBindInfluence *inf;
1581 MDefInfluence *mdinf;
1582 MDefCell *cell;
1583 float center[3], vec[3], maxwidth, totweight;
1584 int a, b, x, y, z, totinside, offset;
1585
1586 /* compute bounding box of the cage mesh */
1587 INIT_MINMAX(mdb->min, mdb->max);
1588
1589 for (a = 0; a < mdb->cage_verts_num; a++) {
1590 minmax_v3v3_v3(mdb->min, mdb->max, mdb->cagecos[a]);
1591 }
1592
1593 /* allocate memory */
1594 mdb->size = (2 << (mmd->gridsize - 1)) + 2;
1595 mdb->size3 = mdb->size * mdb->size * mdb->size;
1596 mdb->tag = MEM_calloc_arrayN<int>(mdb->size3, "MeshDeformBindTag");
1597 mdb->phi = MEM_calloc_arrayN<float>(mdb->size3, "MeshDeformBindPhi");
1598 mdb->totalphi = MEM_calloc_arrayN<float>(mdb->size3, "MeshDeformBindTotalPhi");
1599 mdb->boundisect = static_cast<MDefBoundIsect *(*)[6]>(
1600 MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect"));
1601 mdb->semibound = MEM_calloc_arrayN<int>(mdb->size3, "MDefSemiBound");
1602 mdb->bvhdata = mdb->cagemesh->bvh_corner_tris();
1603 mdb->bvhtree = mdb->bvhdata.tree;
1604 mdb->inside = MEM_calloc_arrayN<int>(mdb->verts_num, "MDefInside");
1605
1606 if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
1607 mdb->dyngrid = MEM_calloc_arrayN<MDefBindInfluence *>(mdb->size3, "MDefDynGrid");
1608 }
1609 else {
1610 mdb->weights = MEM_calloc_arrayN<float>(mdb->verts_num * mdb->cage_verts_num, "MDefWeights");
1611 }
1612
1613 mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
1615
1616 /* Initialize data from `cagedm` for reuse. */
1617 {
1618 Mesh *mesh = mdb->cagemesh;
1619 mdb->cagemesh_cache.faces = mesh->faces();
1620 mdb->cagemesh_cache.corner_verts = mesh->corner_verts();
1621 mdb->cagemesh_cache.corner_tris = mesh->corner_tris();
1622 mdb->cagemesh_cache.tri_faces = mesh->corner_tri_faces();
1623 mdb->cagemesh_cache.face_normals = mesh->face_normals();
1624 }
1625
1626 /* make bounding box equal size in all directions, add padding, and compute
1627 * width of the cells */
1628 maxwidth = -1.0f;
1629 for (a = 0; a < 3; a++) {
1630 maxwidth = std::max(mdb->max[a] - mdb->min[a], maxwidth);
1631 }
1632
1633 for (a = 0; a < 3; a++) {
1634 center[a] = (mdb->min[a] + mdb->max[a]) * 0.5f;
1635 mdb->min[a] = center[a] - maxwidth * 0.5f;
1636 mdb->max[a] = center[a] + maxwidth * 0.5f;
1637
1638 mdb->width[a] = (mdb->max[a] - mdb->min[a]) / (mdb->size - 4);
1639 mdb->min[a] -= 2.1f * mdb->width[a];
1640 mdb->max[a] += 2.1f * mdb->width[a];
1641
1642 mdb->width[a] = (mdb->max[a] - mdb->min[a]) / mdb->size;
1643 mdb->halfwidth[a] = mdb->width[a] * 0.5f;
1644 }
1645
1646 progress_bar(0, "Setting up mesh deform system");
1647
1648 totinside = 0;
1649 for (a = 0; a < mdb->verts_num; a++) {
1650 copy_v3_v3(vec, mdb->vertexcos[a]);
1651 mdb->inside[a] = meshdeform_inside_cage(mdb, vec);
1652 if (mdb->inside[a]) {
1653 totinside++;
1654 }
1655 }
1656 (void)totinside; /* Quiet set-but-unused warning (may be removed). */
1657
1658 /* free temporary MDefBoundIsects */
1660 mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
1661
1662 /* start with all cells untyped */
1663 for (a = 0; a < mdb->size3; a++) {
1664 mdb->tag[a] = MESHDEFORM_TAG_UNTYPED;
1665 }
1666
1667 /* detect intersections and tag boundary cells */
1668 for (z = 0; z < mdb->size; z++) {
1669 for (y = 0; y < mdb->size; y++) {
1670 for (x = 0; x < mdb->size; x++) {
1672 }
1673 }
1674 }
1675
1676 /* compute exterior and interior tags */
1678
1679 for (z = 0; z < mdb->size; z++) {
1680 for (y = 0; y < mdb->size; y++) {
1681 for (x = 0; x < mdb->size; x++) {
1683 }
1684 }
1685 }
1686
1687 /* solve */
1688 meshdeform_matrix_solve(mmd, mdb);
1689
1690 /* assign results */
1691 if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
1692 mmd->influences_num = 0;
1693 for (a = 0; a < mdb->size3; a++) {
1694 for (inf = mdb->dyngrid[a]; inf; inf = inf->next) {
1695 mmd->influences_num++;
1696 }
1697 }
1698
1699 /* convert MDefBindInfluences to smaller MDefInfluences */
1700 mmd->dyngrid = MEM_calloc_arrayN<MDefCell>(mdb->size3, "MDefDynGrid");
1704 offset = 0;
1705 for (a = 0; a < mdb->size3; a++) {
1706 cell = &mmd->dyngrid[a];
1707 cell->offset = offset;
1708
1709 totweight = 0.0f;
1710 mdinf = mmd->dyninfluences + cell->offset;
1711 for (inf = mdb->dyngrid[a]; inf; inf = inf->next, mdinf++) {
1712 mdinf->weight = inf->weight;
1713 mdinf->vertex = inf->vertex;
1714 totweight += mdinf->weight;
1715 cell->influences_num++;
1716 }
1717
1718 if (totweight > 0.0f) {
1719 mdinf = mmd->dyninfluences + cell->offset;
1720 for (b = 0; b < cell->influences_num; b++, mdinf++) {
1721 mdinf->weight /= totweight;
1722 }
1723 }
1724
1725 offset += cell->influences_num;
1726 }
1727
1728 mmd->dynverts = mdb->inside;
1730 mmd->dyngridsize = mdb->size;
1731 copy_v3_v3(mmd->dyncellmin, mdb->min);
1732 mmd->dyncellwidth = mdb->width[0];
1733 MEM_freeN(mdb->dyngrid);
1734 }
1735 else {
1736 mmd->bindweights = mdb->weights;
1737 MEM_freeN(mdb->inside);
1738 }
1739
1740 MEM_freeN(mdb->tag);
1741 MEM_freeN(mdb->phi);
1742 MEM_freeN(mdb->totalphi);
1743 MEM_freeN(mdb->boundisect);
1744 MEM_freeN(mdb->semibound);
1746}
1747
1750 Mesh *cagemesh,
1751 float *vertexcos,
1752 int verts_num,
1753 float cagemat[4][4])
1754{
1755 using namespace blender;
1756 MeshDeformModifierData *mmd_orig = reinterpret_cast<MeshDeformModifierData *>(
1757 BKE_modifier_get_original(object, &mmd->modifier));
1758 MeshDeformBind mdb{};
1759 int a;
1760
1761 waitcursor(1);
1763
1764 /* No need to support other kinds of mesh data as binding is a one-off action. */
1766
1767 /* get mesh and cage mesh */
1768 mdb.vertexcos = static_cast<float (*)[3]>(
1769 MEM_callocN(sizeof(float[3]) * verts_num, "MeshDeformCos"));
1770 mdb.verts_num = verts_num;
1771
1772 mdb.cagemesh = cagemesh;
1774 mdb.cagecos = static_cast<float (*)[3]>(
1775 MEM_callocN(sizeof(*mdb.cagecos) * mdb.cage_verts_num, "MeshDeformBindCos"));
1776 copy_m4_m4(mdb.cagemat, cagemat);
1777
1778 const blender::Span<blender::float3> positions = mdb.cagemesh->vert_positions();
1779 for (a = 0; a < mdb.cage_verts_num; a++) {
1780 copy_v3_v3(mdb.cagecos[a], positions[a]);
1781 }
1782 for (a = 0; a < mdb.verts_num; a++) {
1783 mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a * 3);
1784 }
1785
1786 /* solve */
1787 harmonic_coordinates_bind(mmd_orig, &mdb);
1788
1789 /* assign bind variables */
1790 mmd_orig->bindcagecos = (float *)mdb.cagecos;
1792 mmd_orig->verts_num = mdb.verts_num;
1793 mmd_orig->cage_verts_num = mdb.cage_verts_num;
1794 copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->object_to_world().ptr());
1795
1796 /* transform bindcagecos to world space */
1797 for (a = 0; a < mdb.cage_verts_num; a++) {
1798 mul_m4_v3(mmd_orig->object->object_to_world().ptr(), mmd_orig->bindcagecos + a * 3);
1799 }
1800
1801 /* free */
1802 MEM_freeN(mdb.vertexcos);
1803
1804 /* compact weights */
1805 BKE_modifier_mdef_compact_influences(reinterpret_cast<ModifierData *>(mmd_orig));
1806
1808 waitcursor(0);
1809}
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
ModifierData * BKE_modifier_get_original(const Object *object, ModifierData *md)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_modifier_mdef_compact_influences(ModifierData *md)
#define BLI_INLINE
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
#define BVH_RAYCAST_DIST_MAX
@ BVH_RAYCAST_WATERTIGHT
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
int BLI_bvhtree_ray_cast_ex(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata, int flag)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
MINLINE float max_ff(float a, float b)
#define DEG2RADF(_deg)
bool isect_ray_tri_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
float closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:387
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:100
bool isect_ray_tri_watertight_v3(const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc, const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
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
void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3])
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
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 float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_use_calloc(MemArena *ma) ATTR_NONNULL(1)
#define SNPRINTF_UTF8(dst, format,...)
#define CLAMP(a, b, c)
#define INIT_MINMAX(min, max)
#define UNUSED_VARS(...)
#define UNPACK3(a)
#define UNLIKELY(x)
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_EDIT_MIRROR_TOPO
@ MOD_MDEF_DYNAMIC_BIND
@ OB_MODE_WEIGHT_PAINT
Object is a sort of wrapper for general info.
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, bool use_topology)
Definition meshtools.cc:302
#define WEIGHT_REPLACE
#define WEIGHT_ADD
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
bool closest(btVector3 &v)
AttributeSet attributes
void reserve(int64_t n)
Definition BLI_map.hh:1028
const T * data() const
Definition BLI_array.hh:312
constexpr int64_t size() const
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:481
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
nullptr float
#define str(s)
static float verts[][3]
#define printf(...)
LinearSolver * EIG_linear_solver_new(int num_rows, int num_columns, int num_right_hand_sides)
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 EIG_linear_solver_variable_lock(LinearSolver *solver, int index)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
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_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static char faces[256]
static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
void heat_bone_weighting(Object *ob, Mesh *mesh, float(*verts)[3], int numbones, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float(*root)[3], float(*tip)[3], const bool *selected, const char **r_error_str)
static float meshdeform_boundary_phi(const MeshDeformBind *mdb, const MDefBoundIsect *isect, int cagevert)
static void laplacian_system_delete(LaplacianSystem *sys)
BLI_INLINE void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
static void start_progress_bar()
float laplacian_system_get_solution(LaplacianSystem *sys, int v)
static void laplacian_system_construct_end(LaplacianSystem *sys)
static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
static void heat_set_H(LaplacianSystem *sys, int vertex)
void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value)
static float heat_limit_weight(float weight)
int laplacian_system_solve(LaplacianSystem *sys)
static void heat_ray_tree_create(LaplacianSystem *sys)
static void meshdeform_matrix_add_semibound_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
#define WEIGHT_LIMIT_END
#define WEIGHT_LIMIT_START
static float heat_source_distance(LaplacianSystem *sys, int vertex, int source)
static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z)
void ED_mesh_deform_bind_callback(Object *object, MeshDeformModifierData *mmd, Mesh *cagemesh, float *vertexcos, int verts_num, float cagemat[4][4])
#define MESHDEFORM_MIN_INFLUENCE
static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
static int laplacian_edge_count(const blender::Map< blender::OrderedEdge, int > &edgehash, int v1, int v2)
static void end_progress_bar()
static void progress_bar(int, const char *)
static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z)
static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3)
static void waitcursor(int)
static void error(const char *str)
static LaplacianSystem * laplacian_system_construct_begin(int verts_num, int faces_num, int lsq)
static MDefBoundIsect * meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3])
static int heat_source_closest(LaplacianSystem *sys, int vertex, int source)
BLI_INLINE int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y, int z, int)
static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z)
static void heat_calc_vnormals(LaplacianSystem *sys)
static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void heat_laplacian_create(LaplacianSystem *sys)
static const int MESHDEFORM_OFFSET[7][3]
#define MESHDEFORM_TAG_UNTYPED
#define MESHDEFORM_TAG_BOUNDARY
static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z)
#define MESHDEFORM_TAG_INTERIOR
static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
#define MESHDEFORM_LEN_THRESHOLD
static void heat_system_free(LaplacianSystem *sys)
#define C_WEIGHT
static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z, int cagevert)
void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned)
#define DISTANCE_EPSILON
static void laplacian_increase_edge_count(blender::Map< blender::OrderedEdge, int > &edgehash, int v1, int v2)
#define MESHDEFORM_TAG_EXTERIOR
static float meshdeform_interp_w(MeshDeformBind *mdb, const float *gridvec, float *, int)
void laplacian_begin_solve(LaplacianSystem *sys, int index)
void corner_tris_calc(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< int3 > corner_tris)
float vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
void vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
void vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
const ImplicitSharingInfo * info_for_mem_free(void *data)
VecBase< int32_t, 3 > int3
#define fabsf
LaplacianSystem * sys
float origin[3]
struct IsectRayPrecalc * isect_precalc
float direction[3]
const blender::int3 * corner_tris
blender::Span< int > corner_verts
const blender::int3 ** vltree
float(* fweights)[3]
blender::Map< blender::OrderedEdge, int > edgehash
struct LaplacianSystem::HeatWeighting heat
LinearSolver * context
MDefBindInfluence * next
float poly_weights[0]
float cagemat[4][4]
blender::Span< blender::int3 > corner_tris
blender::Span< int > corner_verts
const BVHTree * bvhtree
blender::Span< int > tri_faces
float(* vertexcos)[3]
blender::bke::BVHTreeFromMesh bvhdata
MemArena * memarena
blender::OffsetIndices< int > faces
MDefBoundIsect *(* boundisect)[6]
float(* cagecos)[3]
blender::Span< blender::float3 > face_normals
struct MeshDeformBind::@002351053344321156015014132137076244054045072031 cagemesh_cache
MDefBindInfluence ** dyngrid
const ImplicitSharingInfoHandle * dyninfluences_sharing_info
const ImplicitSharingInfoHandle * dynverts_sharing_info
const ImplicitSharingInfoHandle * dyngrid_sharing_info
const ImplicitSharingInfoHandle * bindcagecos_sharing_info
MeshDeformBind * mdb
MeshDeformIsect * isec
int corners_num
char editflag
int faces_num
int verts_num
i
Definition text_draw.cc:230
uint len
#define N_(msgid)