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