Blender V4.3
MOD_surfacedeform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_geom.h"
10#include "BLI_math_matrix.h"
11#include "BLI_task.h"
12
13#include "BLT_translation.hh"
14
15#include "DNA_defaults.h"
16#include "DNA_mesh_types.h"
17#include "DNA_meshdata_types.h"
18#include "DNA_object_types.h"
19#include "DNA_screen_types.h"
20
21#include "BKE_bvhutils.hh"
22#include "BKE_deform.hh"
23#include "BKE_lib_query.hh"
24#include "BKE_mesh.hh"
25#include "BKE_mesh_wrapper.hh"
26#include "BKE_modifier.hh"
27
28#include "UI_interface.hh"
29#include "UI_resources.hh"
30
31#include "BLO_read_write.hh"
32
33#include "RNA_access.hh"
34#include "RNA_prototypes.hh"
35
36#include "DEG_depsgraph.hh"
37
38#include "MEM_guardedalloc.h"
39
40#include "MOD_ui_common.hh"
41#include "MOD_util.hh"
42
47
50 uint num; /* Careful, this is twice the number of faces (avoids an extra loop) */
51};
52
58};
59
85
158
164
174
175/* Bind result values */
176enum {
183};
184
185/* Infinite weight flags */
186enum {
190};
191
200
201static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
202{
204
205 /* Ask for vertex groups if we need them. */
206 if (smd->defgrp_name[0] != '\0') {
207 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
208 }
209}
210
211static void free_data(ModifierData *md)
212{
214
215 if (smd->verts) {
216 for (int i = 0; i < smd->bind_verts_num; i++) {
217 if (smd->verts[i].binds) {
218 for (int j = 0; j < smd->verts[i].binds_num; j++) {
221 }
222 MEM_freeN(smd->verts[i].binds);
223 }
224 }
225
226 MEM_SAFE_FREE(smd->verts);
227 }
228}
229
230static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
231{
234
236
237 if (smd->verts) {
238 tsmd->verts = static_cast<SDefVert *>(MEM_dupallocN(smd->verts));
239
240 for (int i = 0; i < smd->bind_verts_num; i++) {
241 if (smd->verts[i].binds) {
242 tsmd->verts[i].binds = static_cast<SDefBind *>(MEM_dupallocN(smd->verts[i].binds));
243
244 for (int j = 0; j < smd->verts[i].binds_num; j++) {
245 if (smd->verts[i].binds[j].vert_inds) {
246 tsmd->verts[i].binds[j].vert_inds = static_cast<uint *>(
247 MEM_dupallocN(smd->verts[i].binds[j].vert_inds));
248 }
249
250 if (smd->verts[i].binds[j].vert_weights) {
251 tsmd->verts[i].binds[j].vert_weights = static_cast<float *>(
253 }
254 }
255 }
256 }
257 }
258}
259
260static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
261{
263
264 walk(user_data, ob, (ID **)&smd->target, IDWALK_NOP);
265}
266
268{
270 if (smd->target != nullptr) {
272 ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier");
273 }
274}
275
276static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges,
277 SDefAdjacency *const adj_ref,
278 SDefEdgePolys *const edge_polys)
279{
280 MEM_freeN(edge_polys);
281
282 MEM_freeN(adj_ref);
283
284 MEM_freeN(vert_edges);
285}
286
289 const blender::Span<int> corner_edges,
290 SDefAdjacencyArray *const vert_edges,
291 SDefAdjacency *adj,
292 SDefEdgePolys *const edge_polys)
293{
294 /* Find polygons adjacent to edges. */
295 for (const int i : polys.index_range()) {
296 for (const int edge_i : corner_edges.slice(polys[i])) {
297 if (edge_polys[edge_i].num == 0) {
298 edge_polys[edge_i].polys[0] = i;
299 edge_polys[edge_i].polys[1] = -1;
300 edge_polys[edge_i].num++;
301 }
302 else if (edge_polys[edge_i].num == 1) {
303 edge_polys[edge_i].polys[1] = i;
304 edge_polys[edge_i].num++;
305 }
306 else {
308 }
309 }
310 }
311
312 /* Find edges adjacent to vertices */
313 for (const int i : edges.index_range()) {
314 const blender::int2 &edge = edges[i];
315 adj->next = vert_edges[edge[0]].first;
316 adj->index = i;
317 vert_edges[edge[0]].first = adj;
318 vert_edges[edge[0]].num += edge_polys[i].num;
319 adj++;
320
321 adj->next = vert_edges[edge[1]].first;
322 adj->index = i;
323 vert_edges[edge[1]].first = adj;
324 vert_edges[edge[1]].num += edge_polys[i].num;
325 adj++;
326 }
327
329}
330
332 const int *const corner_verts,
333 const int *const corner_edges,
334 const uint edge,
335 const uint num)
336{
337 bool found = false;
338
339 for (int i = 0; i < num; i++) {
340 if (corner_edges[i] == edge) {
341 found = true;
342 }
343 if (found) {
344 *indices = corner_verts[i];
345 indices++;
346 }
347 }
348
349 /* Fill in remaining vertex indices that occur before the edge */
350 for (int i = 0; corner_edges[i] != edge; i++) {
351 *indices = corner_verts[i];
352 indices++;
353 }
354}
355
357 const int *const corner_verts,
358 const uint loopstart,
359 const uint num)
360{
361 for (int i = loopstart; i < num; i++) {
362 *indices = corner_verts[i];
363 indices++;
364 }
365
366 for (int i = 0; i < loopstart; i++) {
367 *indices = corner_verts[i];
368 indices++;
369 }
370}
371
372BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3])
373{
374 BVHTreeNearest nearest{};
375 nearest.dist_sq = FLT_MAX;
376 nearest.index = -1;
377
378 float t_point[3];
379 float max_dist = FLT_MAX;
380 float dist;
381 uint index = 0;
382
383 mul_v3_m4v3(t_point, data->imat, point_co);
384
386 data->treeData->tree, t_point, &nearest, data->treeData->nearest_callback, data->treeData);
387
388 const blender::IndexRange face = data->polys[data->tri_faces[nearest.index]];
389
390 for (int i = 0; i < face.size(); i++) {
391 const int edge_i = data->corner_edges[face.start() + i];
392 const blender::int2 &edge = data->edges[edge_i];
394 point_co, data->targetCos[edge[0]], data->targetCos[edge[1]]);
395
396 if (dist < max_dist) {
397 max_dist = dist;
398 index = edge_i;
399 }
400 }
401
402 const blender::int2 &edge = data->edges[index];
403 if (len_squared_v3v3(point_co, data->targetCos[edge[0]]) <
404 len_squared_v3v3(point_co, data->targetCos[edge[1]]))
405 {
406 return edge[0];
407 }
408
409 return edge[1];
410}
411
412BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
413{
414 float prev_co[2], prev_prev_co[2];
415 float curr_vec[2], prev_vec[2];
416
417 if (!is_poly_convex_v2(coords, nr)) {
419 }
420
421 copy_v2_v2(prev_prev_co, coords[nr - 2]);
422 copy_v2_v2(prev_co, coords[nr - 1]);
423 sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]);
424 normalize_v2(prev_vec);
425
426 for (int i = 0; i < nr; i++) {
427 sub_v2_v2v2(curr_vec, coords[i], prev_co);
428
429 /* Check overlap between directly adjacent vertices. */
430 const float curr_len = normalize_v2(curr_vec);
431 if (curr_len < FLT_EPSILON) {
433 }
434
435 /* Check overlap between vertices skipping one. */
436 if (len_squared_v2v2(prev_prev_co, coords[i]) < FLT_EPSILON * FLT_EPSILON) {
438 }
439
440 /* Check for adjacent parallel edges. */
441 if (1.0f - dot_v2v2(prev_vec, curr_vec) < FLT_EPSILON) {
443 }
444
445 copy_v2_v2(prev_prev_co, prev_co);
446 copy_v2_v2(prev_co, coords[i]);
447 copy_v2_v2(prev_vec, curr_vec);
448 }
449
451}
452
453static void freeBindData(SDefBindWeightData *const bwdata)
454{
455 SDefBindPoly *bpoly = bwdata->bind_polys;
456
457 if (bwdata->bind_polys) {
458 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
459 MEM_SAFE_FREE(bpoly->coords);
460 MEM_SAFE_FREE(bpoly->coords_v2);
461 }
462
463 MEM_freeN(bwdata->bind_polys);
464 }
465
466 MEM_freeN(bwdata);
467}
468
469BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle)
470{
471 return sinf(min_ff(point_angle / edgemid_angle, 1) * M_PI_2);
472}
473
475 const float point_co[3])
476{
477 const uint nearest = nearestVert(data, point_co);
478 const SDefAdjacency *const vert_edges = data->vert_edges[nearest].first;
479 const SDefEdgePolys *const edge_polys = data->edge_polys;
480
481 const SDefAdjacency *vedge;
482
483 SDefBindWeightData *bwdata;
484 SDefBindPoly *bpoly;
485
486 const float world[3] = {0.0f, 0.0f, 1.0f};
487 float avg_point_dist = 0.0f;
488 float tot_weight = 0.0f;
489 int inf_weight_flags = 0;
490
491 bwdata = static_cast<SDefBindWeightData *>(MEM_callocN(sizeof(*bwdata), "SDefBindWeightData"));
492 if (bwdata == nullptr) {
493 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
494 return nullptr;
495 }
496
497 bwdata->faces_num = data->vert_edges[nearest].num / 2;
498
499 bpoly = static_cast<SDefBindPoly *>(
500 MEM_calloc_arrayN(bwdata->faces_num, sizeof(*bpoly), "SDefBindPoly"));
501 if (bpoly == nullptr) {
502 freeBindData(bwdata);
503 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
504 return nullptr;
505 }
506
507 bwdata->bind_polys = bpoly;
508
509 /* Loop over all adjacent edges,
510 * and build the #SDefBindPoly data for each face adjacent to those. */
511 for (vedge = vert_edges; vedge; vedge = vedge->next) {
512 uint edge_ind = vedge->index;
513
514 for (int i = 0; i < edge_polys[edge_ind].num; i++) {
515 {
516 bpoly = bwdata->bind_polys;
517
518 for (int j = 0; j < bwdata->faces_num; bpoly++, j++) {
519 /* If coords isn't allocated, we have reached the first uninitialized `bpoly`. */
520 if ((bpoly->index == edge_polys[edge_ind].polys[i]) || (!bpoly->coords)) {
521 break;
522 }
523 }
524 }
525
526 /* Check if face was already created by another edge or still has to be initialized */
527 if (!bpoly->coords) {
528 float angle;
529 float axis[3];
530 float tmp_vec_v2[2];
531 int is_poly_valid;
532
533 bpoly->index = edge_polys[edge_ind].polys[i];
534 bpoly->coords = nullptr;
535 bpoly->coords_v2 = nullptr;
536
537 /* Copy face data */
538 const blender::IndexRange face = data->polys[bpoly->index];
539
540 bpoly->verts_num = face.size();
541 bpoly->loopstart = face.start();
542
543 bpoly->coords = static_cast<float(*)[3]>(
544 MEM_malloc_arrayN(face.size(), sizeof(*bpoly->coords), "SDefBindPolyCoords"));
545 if (bpoly->coords == nullptr) {
546 freeBindData(bwdata);
547 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
548 return nullptr;
549 }
550
551 bpoly->coords_v2 = static_cast<float(*)[2]>(
552 MEM_malloc_arrayN(face.size(), sizeof(*bpoly->coords_v2), "SDefBindPolyCoords_v2"));
553 if (bpoly->coords_v2 == nullptr) {
554 freeBindData(bwdata);
555 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
556 return nullptr;
557 }
558
559 for (int j = 0; j < face.size(); j++) {
560 const int vert_i = data->corner_verts[face.start() + j];
561 const int edge_i = data->corner_edges[face.start() + j];
562 copy_v3_v3(bpoly->coords[j], data->targetCos[vert_i]);
563
564 /* Find corner and edge indices within face loop array */
565 if (vert_i == nearest) {
566 bpoly->corner_ind = j;
567 bpoly->edge_vert_inds[0] = (j == 0) ? (face.size() - 1) : (j - 1);
568 bpoly->edge_vert_inds[1] = (j == face.size() - 1) ? (0) : (j + 1);
569
570 bpoly->edge_inds[0] = data->corner_edges[face.start() + bpoly->edge_vert_inds[0]];
571 bpoly->edge_inds[1] = edge_i;
572 }
573 }
574
575 /* Compute polygons parametric data. */
576 mid_v3_v3_array(bpoly->centroid, bpoly->coords, face.size());
577 normal_poly_v3(bpoly->normal, bpoly->coords, face.size());
578
579 /* Compute face skew angle and axis */
580 angle = angle_normalized_v3v3(bpoly->normal, world);
581
582 cross_v3_v3v3(axis, bpoly->normal, world);
583 normalize_v3(axis);
584
585 /* Map coords onto 2d normal plane. */
586 map_to_plane_axis_angle_v2_v3v3fl(bpoly->point_v2, point_co, axis, angle);
587
588 zero_v2(bpoly->centroid_v2);
589 for (int j = 0; j < face.size(); j++) {
590 map_to_plane_axis_angle_v2_v3v3fl(bpoly->coords_v2[j], bpoly->coords[j], axis, angle);
591 madd_v2_v2fl(bpoly->centroid_v2, bpoly->coords_v2[j], 1.0f / face.size());
592 }
593
594 is_poly_valid = isPolyValid(bpoly->coords_v2, face.size());
595
596 if (is_poly_valid != MOD_SDEF_BIND_RESULT_SUCCESS) {
597 freeBindData(bwdata);
598 data->success = is_poly_valid;
599 return nullptr;
600 }
601
602 bpoly->inside = isect_point_poly_v2(bpoly->point_v2, bpoly->coords_v2, face.size());
603
604 /* Initialize weight components */
605 bpoly->weight_angular = 1.0f;
606 bpoly->weight_dist_proj = len_v2v2(bpoly->centroid_v2, bpoly->point_v2);
607 bpoly->weight_dist = len_v3v3(bpoly->centroid, point_co);
608
609 avg_point_dist += bpoly->weight_dist;
610
611 /* Common vertex coordinates. */
612 const float *const vert0_v2 = bpoly->coords_v2[bpoly->edge_vert_inds[0]];
613 const float *const vert1_v2 = bpoly->coords_v2[bpoly->edge_vert_inds[1]];
614 const float *const corner_v2 = bpoly->coords_v2[bpoly->corner_ind];
615
616 /* Compute centroid to mid-edge vectors */
617 mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0], vert0_v2, corner_v2);
618 mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1], vert1_v2, corner_v2);
619
620 sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2);
621 sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2);
622
625
626 /* Compute face scales with respect to the two edges. */
627 bpoly->scales[0] = dist_to_line_v2(bpoly->centroid_v2, vert0_v2, corner_v2);
628 bpoly->scales[1] = dist_to_line_v2(bpoly->centroid_v2, vert1_v2, corner_v2);
629
630 /* Compute the angle between the edge mid vectors. */
632 bpoly->cent_edgemid_vecs_v2[1]);
633
634 /* Compute the angles between the corner and the edge mid vectors. The angles
635 * are computed signed in order to correctly clamp point_edgemid_angles later. */
636 float corner_angles[2];
637
638 sub_v2_v2v2(tmp_vec_v2, corner_v2, bpoly->centroid_v2);
639 normalize_v2(tmp_vec_v2);
640
641 corner_angles[0] = angle_signed_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[0]);
642 corner_angles[1] = angle_signed_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[1]);
643
644 bpoly->corner_edgemid_angles[0] = fabsf(corner_angles[0]);
645 bpoly->corner_edgemid_angles[1] = fabsf(corner_angles[1]);
646
647 /* Verify that the computed values are valid (the face isn't somehow
648 * degenerate despite having passed isPolyValid). */
649 if (bpoly->scales[0] < FLT_EPSILON || bpoly->scales[1] < FLT_EPSILON ||
650 bpoly->edgemid_angle < FLT_EPSILON || bpoly->corner_edgemid_angles[0] < FLT_EPSILON ||
651 bpoly->corner_edgemid_angles[1] < FLT_EPSILON)
652 {
653 freeBindData(bwdata);
654 data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
655 return nullptr;
656 }
657
658 /* Check for infinite weights, and compute angular data otherwise. */
659 if (bpoly->weight_dist < FLT_EPSILON) {
660 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
661 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
662 }
663 else if (bpoly->weight_dist_proj < FLT_EPSILON) {
664 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
665 }
666 else {
667 /* Compute angles between the point and the edge mid vectors. */
668 float cent_point_vec[2], point_angles[2];
669
670 sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2);
671 normalize_v2(cent_point_vec);
672
673 point_angles[0] = angle_signed_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[0]) *
674 signf(corner_angles[0]);
675 point_angles[1] = angle_signed_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[1]) *
676 signf(corner_angles[1]);
677
678 if (point_angles[0] <= 0 && point_angles[1] <= 0) {
679 /* If the point is outside the corner formed by the edge mid vectors,
680 * choose to clamp the closest side and flip the other. */
681 if (point_angles[0] < point_angles[1]) {
682 point_angles[0] = bpoly->edgemid_angle - point_angles[1];
683 }
684 else {
685 point_angles[1] = bpoly->edgemid_angle - point_angles[0];
686 }
687 }
688
689 bpoly->point_edgemid_angles[0] = max_ff(0, point_angles[0]);
690 bpoly->point_edgemid_angles[1] = max_ff(0, point_angles[1]);
691
692 /* Compute the distance scale for the corner. The base value is the orthogonal
693 * distance from the corner to the chord, scaled by `sqrt(2)` to preserve the old
694 * values in case of a square grid. This doesn't use the centroid because the
695 * corner_triS method only uses these three vertices. */
696 bpoly->scale_mid = area_tri_v2(vert0_v2, corner_v2, vert1_v2) /
697 len_v2v2(vert0_v2, vert1_v2) * sqrtf(2);
698
699 if (bpoly->inside) {
700 /* When inside, interpolate to centroid-based scale close to the center. */
701 float min_dist = min_ff(bpoly->scales[0], bpoly->scales[1]);
702
703 bpoly->scale_mid = interpf(bpoly->scale_mid,
704 (bpoly->scales[0] + bpoly->scales[1]) / 2,
705 min_ff(bpoly->weight_dist_proj / min_dist, 1));
706 }
707
708 /* Verify that the additional computed values are valid. */
709 if (bpoly->scale_mid < FLT_EPSILON ||
710 bpoly->point_edgemid_angles[0] + bpoly->point_edgemid_angles[1] < FLT_EPSILON)
711 {
712 freeBindData(bwdata);
713 data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
714 return nullptr;
715 }
716 }
717 }
718 }
719 }
720
721 avg_point_dist /= bwdata->faces_num;
722
723 /* If weights 1 and 2 are not infinite, loop over all adjacent edges again,
724 * and build adjacency dependent angle data (depends on all polygons having been computed) */
725 if (!inf_weight_flags) {
726 for (vedge = vert_edges; vedge; vedge = vedge->next) {
727 SDefBindPoly *bpolys[2];
728 const SDefEdgePolys *epolys;
729 float ang_weights[2];
730 uint edge_ind = vedge->index;
731 uint edge_on_poly[2];
732
733 epolys = &edge_polys[edge_ind];
734
735 /* Find bind polys corresponding to the edge's adjacent polys */
736 bpoly = bwdata->bind_polys;
737
738 for (int i = 0, j = 0; (i < bwdata->faces_num) && (j < epolys->num); bpoly++, i++) {
739 if (ELEM(bpoly->index, epolys->polys[0], epolys->polys[1])) {
740 bpolys[j] = bpoly;
741
742 if (bpoly->edge_inds[0] == edge_ind) {
743 edge_on_poly[j] = 0;
744 }
745 else {
746 edge_on_poly[j] = 1;
747 }
748
749 j++;
750 }
751 }
752
753 /* Compute angular weight component */
754 if (epolys->num == 1) {
755 ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
756 bpolys[0]->edgemid_angle);
757 bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0];
758 }
759 else if (epolys->num == 2) {
760 ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
761 bpolys[0]->edgemid_angle);
762 ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]],
763 bpolys[1]->edgemid_angle);
764
765 bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1];
766 bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1];
767 }
768 }
769 }
770
771 /* Compute scaling and falloff:
772 * - Scale all weights if no infinite weight is found.
773 * - Scale only un-projected weight if projected weight is infinite.
774 * - Scale none if both are infinite. */
775 if (!inf_weight_flags) {
776 bpoly = bwdata->bind_polys;
777
778 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
779 float corner_angle_weights[2];
780 float scale_weight, sqr, inv_sqr;
781
782 corner_angle_weights[0] = bpoly->point_edgemid_angles[0] / bpoly->corner_edgemid_angles[0];
783 corner_angle_weights[1] = bpoly->point_edgemid_angles[1] / bpoly->corner_edgemid_angles[1];
784
785 if (isnan(corner_angle_weights[0]) || isnan(corner_angle_weights[1])) {
786 freeBindData(bwdata);
787 data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
788 return nullptr;
789 }
790
791 /* Find which edge the point is closer to */
792 if (corner_angle_weights[0] < corner_angle_weights[1]) {
793 bpoly->dominant_edge = 0;
794 bpoly->dominant_angle_weight = corner_angle_weights[0];
795 }
796 else {
797 bpoly->dominant_edge = 1;
798 bpoly->dominant_angle_weight = corner_angle_weights[1];
799 }
800
801 /* Check for invalid weights just in case computations fail. */
802 if (bpoly->dominant_angle_weight < 0 || bpoly->dominant_angle_weight > 1) {
803 freeBindData(bwdata);
804 data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
805 return nullptr;
806 }
807
809
810 /* Compute quadratic angular scale interpolation weight */
811 {
812 const float edge_angle_a = bpoly->point_edgemid_angles[bpoly->dominant_edge];
813 const float edge_angle_b = bpoly->point_edgemid_angles[!bpoly->dominant_edge];
814 /* Clamp so skinny faces with near zero `edgemid_angle`
815 * won't cause numeric problems. see #81988. */
816 scale_weight = edge_angle_a / max_ff(edge_angle_a, bpoly->edgemid_angle);
817 scale_weight /= scale_weight + (edge_angle_b / max_ff(edge_angle_b, bpoly->edgemid_angle));
818 }
819
820 sqr = scale_weight * scale_weight;
821 inv_sqr = 1.0f - scale_weight;
822 inv_sqr *= inv_sqr;
823 scale_weight = sqr / (sqr + inv_sqr);
824
825 BLI_assert(scale_weight >= 0 && scale_weight <= 1);
826
827 /* Compute interpolated scale (no longer need the individual scales,
828 * so simply storing the result over the scale in index zero) */
829 bpoly->scales[0] = interpf(bpoly->scale_mid,
830 interpf(bpoly->scales[!bpoly->dominant_edge],
831 bpoly->scales[bpoly->dominant_edge],
832 scale_weight),
833 bpoly->dominant_angle_weight);
834
835 /* Scale the point distance weights, and introduce falloff */
836 bpoly->weight_dist_proj /= bpoly->scales[0];
837 bpoly->weight_dist_proj = powf(bpoly->weight_dist_proj, data->falloff);
838
839 bpoly->weight_dist /= avg_point_dist;
840 bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
841
842 /* Re-check for infinite weights, now that all scalings and interpolations are computed */
843 if (bpoly->weight_dist < FLT_EPSILON) {
844 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
845 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
846 }
847 else if (bpoly->weight_dist_proj < FLT_EPSILON) {
848 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
849 }
850 else if (bpoly->weight_angular < FLT_EPSILON) {
851 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_ANGULAR;
852 }
853 }
854 }
855 else if (!(inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST)) {
856 bpoly = bwdata->bind_polys;
857
858 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
859 /* Scale the point distance weight by average point distance, and introduce falloff */
860 bpoly->weight_dist /= avg_point_dist;
861 bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
862
863 /* Re-check for infinite weights, now that all scalings and interpolations are computed */
864 if (bpoly->weight_dist < FLT_EPSILON) {
865 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
866 }
867 }
868 }
869
870 /* Final loop, to compute actual weights */
871 bpoly = bwdata->bind_polys;
872
873 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
874 /* Weight computation from components */
875 if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST) {
876 bpoly->weight = bpoly->weight_dist < FLT_EPSILON ? 1.0f : 0.0f;
877 }
878 else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ) {
879 bpoly->weight = bpoly->weight_dist_proj < FLT_EPSILON ? 1.0f / bpoly->weight_dist : 0.0f;
880 }
881 else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_ANGULAR) {
882 bpoly->weight = bpoly->weight_angular < FLT_EPSILON ?
883 1.0f / bpoly->weight_dist_proj / bpoly->weight_dist :
884 0.0f;
885 }
886 else {
887 bpoly->weight = 1.0f / bpoly->weight_angular / bpoly->weight_dist_proj / bpoly->weight_dist;
888 }
889
890 /* Apply after other kinds of scaling so the faces corner angle is always
891 * scaled in a uniform way, preventing heavily sub-divided triangle fans
892 * from having a lop-sided influence on the weighting, see #81988. */
893 bpoly->weight *= bpoly->edgemid_angle / M_PI;
894
895 tot_weight += bpoly->weight;
896 }
897
898 bpoly = bwdata->bind_polys;
899
900 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
901 bpoly->weight /= tot_weight;
902
903 /* Evaluate if this face is relevant to bind */
904 /* Even though the weights should add up to 1.0,
905 * the losses of weights smaller than epsilon here
906 * should be negligible... */
907 if (bpoly->weight >= FLT_EPSILON) {
908 if (bpoly->inside) {
909 bwdata->binds_num += 1;
910 }
911 else {
912 if (bpoly->dominant_angle_weight < FLT_EPSILON ||
913 1.0f - bpoly->dominant_angle_weight < FLT_EPSILON)
914 {
915 bwdata->binds_num += 1;
916 }
917 else {
918 bwdata->binds_num += 2;
919 }
920 }
921 }
922 }
923
924 return bwdata;
925}
926
927BLI_INLINE float computeNormalDisplacement(const float point_co[3],
928 const float point_co_proj[3],
929 const float normal[3])
930{
931 float disp_vec[3];
932 float normal_dist;
933
934 sub_v3_v3v3(disp_vec, point_co, point_co_proj);
935 normal_dist = len_v3(disp_vec);
936
937 if (dot_v3v3(disp_vec, normal) < 0) {
938 normal_dist *= -1;
939 }
940
941 return normal_dist;
942}
943
944static void bindVert(void *__restrict userdata,
945 const int index,
946 const TaskParallelTLS *__restrict /*tls*/)
947{
948 SDefBindCalcData *const data = (SDefBindCalcData *)userdata;
949 float point_co[3];
950 float point_co_proj[3];
951
952 SDefBindWeightData *bwdata;
953 SDefVert *sdvert = data->bind_verts + index;
954 SDefBindPoly *bpoly;
955 SDefBind *sdbind;
956
957 sdvert->vertex_idx = index;
958
959 if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) {
960 sdvert->binds = nullptr;
961 sdvert->binds_num = 0;
962 return;
963 }
964
965 if (data->sparse_bind) {
966 float weight = 0.0f;
967
968 if (data->dvert && data->defgrp_index != -1) {
969 weight = BKE_defvert_find_weight(&data->dvert[index], data->defgrp_index);
970 }
971
972 if (data->invert_vgroup) {
973 weight = 1.0f - weight;
974 }
975
976 if (weight <= 0) {
977 sdvert->binds = nullptr;
978 sdvert->binds_num = 0;
979 return;
980 }
981 }
982
983 copy_v3_v3(point_co, data->vertexCos[index]);
984 bwdata = computeBindWeights(data, point_co);
985
986 if (bwdata == nullptr) {
987 sdvert->binds = nullptr;
988 sdvert->binds_num = 0;
989 return;
990 }
991
992 sdvert->binds = static_cast<SDefBind *>(
993 MEM_calloc_arrayN(bwdata->binds_num, sizeof(*sdvert->binds), "SDefVertBindData"));
994 if (sdvert->binds == nullptr) {
995 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
996 sdvert->binds_num = 0;
997 return;
998 }
999
1000 sdvert->binds_num = bwdata->binds_num;
1001
1002 sdbind = sdvert->binds;
1003
1004 bpoly = bwdata->bind_polys;
1005
1006 for (int i = 0; i < bwdata->binds_num; bpoly++) {
1007 if (bpoly->weight >= FLT_EPSILON) {
1008 if (bpoly->inside) {
1009 sdbind->influence = bpoly->weight;
1010 sdbind->verts_num = bpoly->verts_num;
1011
1012 sdbind->mode = MOD_SDEF_MODE_NGONS;
1013 sdbind->vert_weights = static_cast<float *>(MEM_malloc_arrayN(
1014 bpoly->verts_num, sizeof(*sdbind->vert_weights), "SDefNgonVertWeights"));
1015 if (sdbind->vert_weights == nullptr) {
1016 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
1017 return;
1018 }
1019
1020 sdbind->vert_inds = static_cast<uint *>(
1021 MEM_malloc_arrayN(bpoly->verts_num, sizeof(*sdbind->vert_inds), "SDefNgonVertInds"));
1022 if (sdbind->vert_inds == nullptr) {
1023 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
1024 return;
1025 }
1026
1028 sdbind->vert_weights, bpoly->coords_v2, bpoly->verts_num, bpoly->point_v2);
1029
1030 /* Re-project vert based on weights and original face verts,
1031 * to reintroduce face non-planarity */
1032 zero_v3(point_co_proj);
1033 for (int j = 0; j < bpoly->verts_num; j++) {
1034 const int vert_i = data->corner_verts[bpoly->loopstart + j];
1035 madd_v3_v3fl(point_co_proj, bpoly->coords[j], sdbind->vert_weights[j]);
1036 sdbind->vert_inds[j] = vert_i;
1037 }
1038
1039 sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
1040
1041 sdbind++;
1042 i++;
1043 }
1044 else {
1045 float tmp_vec[3];
1046 float cent[3], norm[3];
1047 float v1[3], v2[3], v3[3];
1048
1049 if (1.0f - bpoly->dominant_angle_weight >= FLT_EPSILON) {
1050 sdbind->influence = bpoly->weight * (1.0f - bpoly->dominant_angle_weight);
1051 sdbind->verts_num = bpoly->verts_num;
1052
1053 sdbind->mode = MOD_SDEF_MODE_CENTROID;
1054 sdbind->vert_weights = static_cast<float *>(
1055 MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefCentVertWeights"));
1056 if (sdbind->vert_weights == nullptr) {
1057 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
1058 return;
1059 }
1060
1061 sdbind->vert_inds = static_cast<uint *>(
1062 MEM_malloc_arrayN(bpoly->verts_num, sizeof(*sdbind->vert_inds), "SDefCentVertInds"));
1063 if (sdbind->vert_inds == nullptr) {
1064 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
1065 return;
1066 }
1067
1069 &data->corner_verts[bpoly->loopstart],
1070 &data->corner_edges[bpoly->loopstart],
1071 bpoly->edge_inds[bpoly->dominant_edge],
1072 bpoly->verts_num);
1073
1074 copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
1075 copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
1076 copy_v3_v3(v3, bpoly->centroid);
1077
1078 mid_v3_v3v3v3(cent, v1, v2, v3);
1079 normal_tri_v3(norm, v1, v2, v3);
1080
1081 add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
1082
1083 /* We are sure the line is not parallel to the plane.
1084 * Checking return value just to avoid warning... */
1085 if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
1086 BLI_assert(false);
1087 }
1088
1089 interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
1090
1091 sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
1092
1093 sdbind++;
1094 i++;
1095 }
1096
1097 if (bpoly->dominant_angle_weight >= FLT_EPSILON) {
1098 sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight;
1099 sdbind->verts_num = bpoly->verts_num;
1100
1102 sdbind->vert_weights = static_cast<float *>(
1103 MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefTriVertWeights"));
1104 if (sdbind->vert_weights == nullptr) {
1105 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
1106 return;
1107 }
1108
1109 sdbind->vert_inds = static_cast<uint *>(
1110 MEM_malloc_arrayN(bpoly->verts_num, sizeof(*sdbind->vert_inds), "SDefTriVertInds"));
1111 if (sdbind->vert_inds == nullptr) {
1112 data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
1113 return;
1114 }
1115
1117 &data->corner_verts[bpoly->loopstart],
1118 bpoly->edge_vert_inds[0],
1119 bpoly->verts_num);
1120
1121 copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
1122 copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
1123 copy_v3_v3(v3, data->targetCos[sdbind->vert_inds[2]]);
1124
1125 mid_v3_v3v3v3(cent, v1, v2, v3);
1126 normal_tri_v3(norm, v1, v2, v3);
1127
1128 add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
1129
1130 /* We are sure the line is not parallel to the plane.
1131 * Checking return value just to avoid warning... */
1132 if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
1133 BLI_assert(false);
1134 }
1135
1136 interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
1137
1138 sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
1139
1140 sdbind++;
1141 i++;
1142 }
1143 }
1144 }
1145 }
1146
1147 freeBindData(bwdata);
1148}
1149
1150/* Remove vertices without bind data from the bind array. */
1152{
1153 smd->bind_verts_num = 0;
1154
1155 for (uint i = 0; i < smd->mesh_verts_num; i++) {
1156 if (smd->verts[i].binds_num > 0) {
1157 smd->verts[smd->bind_verts_num++] = smd->verts[i];
1158 }
1159 }
1160
1161 smd->verts = static_cast<SDefVert *>(MEM_reallocN_id(
1162 smd->verts, sizeof(*smd->verts) * smd->bind_verts_num, "SDefBindVerts (sparse)"));
1163}
1164
1166 SurfaceDeformModifierData *smd_orig,
1167 SurfaceDeformModifierData *smd_eval,
1168 float (*vertexCos)[3],
1169 uint verts_num,
1170 uint target_faces_num,
1171 uint target_verts_num,
1172 Mesh *target,
1173 Mesh *mesh)
1174{
1175 BVHTreeFromMesh treeData = {nullptr};
1176 const blender::Span<blender::float3> positions = target->vert_positions();
1177 const blender::Span<blender::int2> edges = target->edges();
1178 const blender::OffsetIndices polys = target->faces();
1179 const blender::Span<int> corner_verts = target->corner_verts();
1180 const blender::Span<int> corner_edges = target->corner_edges();
1181 uint tedges_num = target->edges_num;
1182 int adj_result;
1183
1184 SDefAdjacencyArray *vert_edges = static_cast<SDefAdjacencyArray *>(
1185 MEM_calloc_arrayN(target_verts_num, sizeof(*vert_edges), "SDefVertEdgeMap"));
1186 if (vert_edges == nullptr) {
1187 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1188 return false;
1189 }
1190
1191 SDefAdjacency *adj_array = static_cast<SDefAdjacency *>(
1192 MEM_malloc_arrayN(tedges_num, 2 * sizeof(*adj_array), "SDefVertEdge"));
1193 if (adj_array == nullptr) {
1194 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1195 MEM_freeN(vert_edges);
1196 return false;
1197 }
1198
1199 SDefEdgePolys *edge_polys = static_cast<SDefEdgePolys *>(
1200 MEM_calloc_arrayN(tedges_num, sizeof(*edge_polys), "SDefEdgeFaceMap"));
1201 if (edge_polys == nullptr) {
1202 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1203 MEM_freeN(vert_edges);
1204 MEM_freeN(adj_array);
1205 return false;
1206 }
1207
1208 smd_orig->verts = static_cast<SDefVert *>(
1209 MEM_malloc_arrayN(verts_num, sizeof(*smd_orig->verts), "SDefBindVerts"));
1210 if (smd_orig->verts == nullptr) {
1211 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1212 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1213 return false;
1214 }
1215
1217 if (treeData.tree == nullptr) {
1218 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1219 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1220 MEM_freeN(smd_orig->verts);
1221 smd_orig->verts = nullptr;
1222 return false;
1223 }
1224
1225 adj_result = buildAdjacencyMap(polys, edges, corner_edges, vert_edges, adj_array, edge_polys);
1226
1227 if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
1229 ob, (ModifierData *)smd_eval, "Target has edges with more than two polygons");
1230 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1231 free_bvhtree_from_mesh(&treeData);
1232 MEM_freeN(smd_orig->verts);
1233 smd_orig->verts = nullptr;
1234 return false;
1235 }
1236
1237 smd_orig->mesh_verts_num = verts_num;
1238 smd_orig->target_verts_num = target_verts_num;
1239 smd_orig->target_polys_num = target_faces_num;
1240
1241 int defgrp_index;
1242 const MDeformVert *dvert;
1243 MOD_get_vgroup(ob, mesh, smd_orig->defgrp_name, &dvert, &defgrp_index);
1244 const bool invert_vgroup = (smd_orig->flags & MOD_SDEF_INVERT_VGROUP) != 0;
1245 const bool sparse_bind = (smd_orig->flags & MOD_SDEF_SPARSE_BIND) != 0;
1246
1247 SDefBindCalcData data{};
1248 data.treeData = &treeData;
1249 data.vert_edges = vert_edges;
1250 data.edge_polys = edge_polys;
1251 data.polys = polys;
1252 data.edges = edges;
1253 data.corner_verts = corner_verts;
1254 data.corner_edges = corner_edges;
1255 data.corner_tris = target->corner_tris();
1256 data.tri_faces = target->corner_tri_faces();
1257 data.targetCos = static_cast<float(*)[3]>(
1258 MEM_malloc_arrayN(target_verts_num, sizeof(float[3]), "SDefTargetBindVertArray"));
1259 data.bind_verts = smd_orig->verts;
1260 data.vertexCos = vertexCos;
1261 data.falloff = smd_orig->falloff;
1262 data.success = MOD_SDEF_BIND_RESULT_SUCCESS;
1263 data.dvert = dvert;
1264 data.defgrp_index = defgrp_index;
1265 data.invert_vgroup = invert_vgroup;
1266 data.sparse_bind = sparse_bind;
1267
1268 if (data.targetCos == nullptr) {
1269 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1270 free_data((ModifierData *)smd_orig);
1271 return false;
1272 }
1273
1274 invert_m4_m4(data.imat, smd_orig->mat);
1275
1276 for (int i = 0; i < target_verts_num; i++) {
1277 mul_v3_m4v3(data.targetCos[i], smd_orig->mat, positions[i]);
1278 }
1279
1280 TaskParallelSettings settings;
1282 settings.use_threading = (verts_num > 10000);
1283 BLI_task_parallel_range(0, verts_num, &data, bindVert, &settings);
1284
1285 MEM_freeN(data.targetCos);
1286
1287 if (sparse_bind) {
1288 compactSparseBinds(smd_orig);
1289 }
1290 else {
1291 smd_orig->bind_verts_num = verts_num;
1292 }
1293
1294 if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
1295 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1296 free_data((ModifierData *)smd_orig);
1297 }
1298 else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
1300 ob, (ModifierData *)smd_eval, "Target has edges with more than two polygons");
1301 free_data((ModifierData *)smd_orig);
1302 }
1303 else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) {
1304 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains concave polygons");
1305 free_data((ModifierData *)smd_orig);
1306 }
1307 else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) {
1308 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains overlapping vertices");
1309 free_data((ModifierData *)smd_orig);
1310 }
1311 else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) {
1312 /* I know this message is vague, but I could not think of a way
1313 * to explain this with a reasonably sized message.
1314 * Though it shouldn't really matter all that much,
1315 * because this is very unlikely to occur */
1316 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains invalid polygons");
1317 free_data((ModifierData *)smd_orig);
1318 }
1319 else if (smd_orig->bind_verts_num == 0 || !smd_orig->verts) {
1320 data.success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
1321 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "No vertices were bound");
1322 free_data((ModifierData *)smd_orig);
1323 }
1324
1325 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1326 free_bvhtree_from_mesh(&treeData);
1327
1328 return data.success == 1;
1329}
1330
1331static void deformVert(void *__restrict userdata,
1332 const int index,
1333 const TaskParallelTLS *__restrict /*tls*/)
1334{
1335 const SDefDeformData *const data = (SDefDeformData *)userdata;
1336 const SDefBind *sdbind = data->bind_verts[index].binds;
1337 const int sdbind_num = data->bind_verts[index].binds_num;
1338 const uint vertex_idx = data->bind_verts[index].vertex_idx;
1339 float *const vertexCos = data->vertexCos[vertex_idx];
1340 float norm[3], temp[3], offset[3];
1341
1342 /* Retrieve the value of the weight vertex group if specified. */
1343 float weight = 1.0f;
1344
1345 if (data->dvert && data->defgrp_index != -1) {
1346 weight = BKE_defvert_find_weight(&data->dvert[vertex_idx], data->defgrp_index);
1347
1348 if (data->invert_vgroup) {
1349 weight = 1.0f - weight;
1350 }
1351 }
1352
1353 /* Check if this vertex will be deformed. If it is not deformed we return and avoid
1354 * unnecessary calculations. */
1355 if (weight == 0.0f) {
1356 return;
1357 }
1358
1359 zero_v3(offset);
1360
1361 int max_verts = 0;
1362 for (int j = 0; j < sdbind_num; j++) {
1363 max_verts = std::max(max_verts, int(sdbind[j].verts_num));
1364 }
1365
1366 /* Allocate a `coords_buffer` that fits all the temp-data. */
1367 blender::Array<blender::float3, 256> coords_buffer(max_verts);
1368
1369 for (int j = 0; j < sdbind_num; j++, sdbind++) {
1370 for (int k = 0; k < sdbind->verts_num; k++) {
1371 copy_v3_v3(coords_buffer[k], data->targetCos[sdbind->vert_inds[k]]);
1372 }
1373
1375 norm, reinterpret_cast<const float(*)[3]>(coords_buffer.data()), sdbind->verts_num);
1376 zero_v3(temp);
1377
1378 switch (sdbind->mode) {
1379 /* ---------- corner_tri mode ---------- */
1381 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
1382 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
1383 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]);
1384 break;
1385 }
1386
1387 /* ---------- ngon mode ---------- */
1388 case MOD_SDEF_MODE_NGONS: {
1389 for (int k = 0; k < sdbind->verts_num; k++) {
1390 madd_v3_v3fl(temp, coords_buffer[k], sdbind->vert_weights[k]);
1391 }
1392 break;
1393 }
1394
1395 /* ---------- centroid mode ---------- */
1397 float cent[3];
1399 cent, reinterpret_cast<const float(*)[3]>(coords_buffer.data()), sdbind->verts_num);
1400
1401 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
1402 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
1403 madd_v3_v3fl(temp, cent, sdbind->vert_weights[2]);
1404 break;
1405 }
1406 }
1407
1408 /* Apply normal offset (generic for all modes) */
1409 madd_v3_v3fl(temp, norm, sdbind->normal_dist);
1410
1411 madd_v3_v3fl(offset, temp, sdbind->influence);
1412 }
1413 /* Subtract the vertex coord to get the deformation offset. */
1414 sub_v3_v3(offset, vertexCos);
1415
1416 /* Add the offset to start coord multiplied by the strength and weight values. */
1417 madd_v3_v3fl(vertexCos, offset, data->strength * weight);
1418}
1419
1421 const ModifierEvalContext *ctx,
1422 float (*vertexCos)[3],
1423 uint verts_num,
1424 Object *ob,
1425 Mesh *mesh)
1426{
1428 Mesh *target;
1429 uint target_verts_num, target_faces_num;
1430
1431 /* Exit function if bind flag is not set (free bind data if any). */
1432 if (!(smd->flags & MOD_SDEF_BIND)) {
1433 if (smd->verts != nullptr) {
1434 if (!DEG_is_active(ctx->depsgraph)) {
1435 BKE_modifier_set_error(ob, md, "Attempt to bind from inactive dependency graph");
1436 return;
1437 }
1438 ModifierData *md_orig = BKE_modifier_get_original(ob, md);
1439 free_data(md_orig);
1440 }
1441 return;
1442 }
1443
1444 Object *ob_target = smd->target;
1446 if (!target) {
1447 BKE_modifier_set_error(ob, md, "No valid target mesh");
1448 return;
1449 }
1450
1451 target_verts_num = BKE_mesh_wrapper_vert_len(target);
1452 target_faces_num = BKE_mesh_wrapper_face_len(target);
1453
1454 /* If not bound, execute bind. */
1455 if (smd->verts == nullptr) {
1456 if (!DEG_is_active(ctx->depsgraph)) {
1457 BKE_modifier_set_error(ob, md, "Attempt to unbind from inactive dependency graph");
1458 return;
1459 }
1460
1462 ob, md);
1463 float tmp_mat[4][4];
1464
1465 invert_m4_m4(tmp_mat, ob->object_to_world().ptr());
1466 mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->object_to_world().ptr());
1467
1468 /* Avoid converting edit-mesh data, binding is an exception. */
1470
1471 if (!surfacedeformBind(ob,
1472 smd_orig,
1473 smd,
1474 vertexCos,
1475 verts_num,
1476 target_faces_num,
1477 target_verts_num,
1478 target,
1479 mesh))
1480 {
1481 smd->flags &= ~MOD_SDEF_BIND;
1482 }
1483 /* Early abort, this is binding 'call', no need to perform whole evaluation. */
1484 return;
1485 }
1486
1487 /* Geometry count on the deforming mesh. */
1488 if (smd->mesh_verts_num != verts_num) {
1490 ob, md, "Vertices changed from %u to %u", smd->mesh_verts_num, verts_num);
1491 return;
1492 }
1493
1494 /* Geometry count on the target mesh. */
1495 if (smd->target_polys_num != target_faces_num && smd->target_verts_num == 0) {
1496 /* Change in the number of polygons does not really imply change in the vertex count, but
1497 * this is how the modifier worked before the vertex count was known. Follow the legacy
1498 * logic without requirement to re-bind the mesh. */
1500 ob, md, "Target polygons changed from %u to %u", smd->target_polys_num, target_faces_num);
1501 return;
1502 }
1503 if (!ELEM(smd->target_verts_num, 0, target_verts_num)) {
1504 if (smd->target_verts_num > target_verts_num) {
1505 /* Number of vertices on the target did reduce. There is no usable recovery from this. */
1507 md,
1508 "Target vertices changed from %u to %u",
1509 smd->target_verts_num,
1510 target_verts_num);
1511 return;
1512 }
1513
1514 /* Assume the increase in the vertex count means that the "new" vertices in the target mesh are
1515 * added after the original ones. This covers typical case when target was at the subdivision
1516 * level 0 and then subdivision was increased (i.e. for the render purposes). */
1517
1519 md,
1520 "Target vertices changed from %u to %u, continuing anyway",
1521 smd->target_verts_num,
1522 target_verts_num);
1523
1524 /* In theory we only need the `smd->verts_num` vertices in the `targetCos` for evaluation, but
1525 * it is not currently possible to request a subset of coordinates: the API expects that the
1526 * caller needs coordinates of all vertices and asserts for it. */
1527 }
1528
1529 /* Early out if modifier would not affect input at all - still *after* the sanity checks
1530 * (and potential binding) above. */
1531 if (smd->strength == 0.0f) {
1532 return;
1533 }
1534
1535 int defgrp_index;
1536 const MDeformVert *dvert;
1537 MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
1538 const bool invert_vgroup = (smd->flags & MOD_SDEF_INVERT_VGROUP) != 0;
1539
1540 /* Actual vertex location update starts here */
1541 SDefDeformData data{};
1542 data.bind_verts = smd->verts;
1543 data.targetCos = static_cast<float(*)[3]>(
1544 MEM_malloc_arrayN(target_verts_num, sizeof(float[3]), "SDefTargetVertArray"));
1545 data.vertexCos = vertexCos;
1546 data.dvert = dvert;
1547 data.defgrp_index = defgrp_index;
1548 data.invert_vgroup = invert_vgroup;
1549 data.strength = smd->strength;
1550
1551 if (data.targetCos != nullptr) {
1553 target, data.targetCos, target_verts_num, smd->mat);
1554
1555 TaskParallelSettings settings;
1557 settings.use_threading = (smd->bind_verts_num > 10000);
1558 BLI_task_parallel_range(0, smd->bind_verts_num, &data, deformVert, &settings);
1559
1560 MEM_freeN(data.targetCos);
1561 }
1562}
1563
1565 const ModifierEvalContext *ctx,
1566 Mesh *mesh,
1568{
1570 ctx,
1571 reinterpret_cast<float(*)[3]>(positions.data()),
1572 positions.size(),
1573 ctx->object,
1574 mesh);
1575}
1576
1577static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
1578{
1580
1581 /* The object type check is only needed here in case we have a placeholder
1582 * object assigned (because the library containing the mesh is missing).
1583 *
1584 * In other cases it should be impossible to have a type mismatch.
1585 */
1586 return (smd->target == nullptr || smd->target->type != OB_MESH) &&
1587 !(smd->verts != nullptr && !(smd->flags & MOD_SDEF_BIND));
1588}
1589
1590static void panel_draw(const bContext * /*C*/, Panel *panel)
1591{
1592 uiLayout *col;
1593 uiLayout *layout = panel->layout;
1594
1595 PointerRNA ob_ptr;
1597
1598 PointerRNA target_ptr = RNA_pointer_get(ptr, "target");
1599
1600 bool is_bound = RNA_boolean_get(ptr, "is_bound");
1601
1602 uiLayoutSetPropSep(layout, true);
1603
1604 col = uiLayoutColumn(layout, false);
1605 uiLayoutSetActive(col, !is_bound);
1606 uiItemR(col, ptr, "target", UI_ITEM_NONE, nullptr, ICON_NONE);
1607 uiItemR(col, ptr, "falloff", UI_ITEM_NONE, nullptr, ICON_NONE);
1608
1609 uiItemR(layout, ptr, "strength", UI_ITEM_NONE, nullptr, ICON_NONE);
1610
1611 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
1612
1613 col = uiLayoutColumn(layout, false);
1614 uiLayoutSetEnabled(col, !is_bound);
1615 uiLayoutSetActive(col, !is_bound && RNA_string_length(ptr, "vertex_group") != 0);
1616 uiItemR(col, ptr, "use_sparse_bind", UI_ITEM_NONE, nullptr, ICON_NONE);
1617
1618 uiItemS(layout);
1619
1620 col = uiLayoutColumn(layout, false);
1621 if (is_bound) {
1622 uiItemO(col, IFACE_("Unbind"), ICON_NONE, "OBJECT_OT_surfacedeform_bind");
1623 }
1624 else {
1626 uiItemO(col, IFACE_("Bind"), ICON_NONE, "OBJECT_OT_surfacedeform_bind");
1627 }
1628 modifier_panel_end(layout, ptr);
1629}
1630
1631static void panel_register(ARegionType *region_type)
1632{
1634}
1635
1636static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
1637{
1639 const bool is_undo = BLO_write_is_undo(writer);
1640
1641 if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
1642 BLI_assert(!ID_IS_LINKED(id_owner));
1643 const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
1644 if (!is_local) {
1645 /* Modifier coming from linked data cannot be bound from an override, so we can remove all
1646 * binding data, can save a significant amount of memory. */
1647 smd.bind_verts_num = 0;
1648 smd.verts = nullptr;
1649 }
1650 }
1651
1653
1654 if (smd.verts != nullptr) {
1655 SDefVert *bind_verts = smd.verts;
1656 BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
1657
1658 for (int i = 0; i < smd.bind_verts_num; i++) {
1659 BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
1660
1661 if (bind_verts[i].binds) {
1662 for (int j = 0; j < bind_verts[i].binds_num; j++) {
1664 writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
1665
1666 if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
1667 {
1668 BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
1669 }
1670 else {
1672 writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_weights);
1673 }
1674 }
1675 }
1676 }
1677 }
1678}
1679
1680static void blend_read(BlendDataReader *reader, ModifierData *md)
1681{
1683
1684 BLO_read_struct_array(reader, SDefVert, smd->bind_verts_num, &smd->verts);
1685
1686 if (smd->verts) {
1687 for (int i = 0; i < smd->bind_verts_num; i++) {
1688 BLO_read_struct_array(reader, SDefBind, smd->verts[i].binds_num, &smd->verts[i].binds);
1689
1690 if (smd->verts[i].binds) {
1691 for (int j = 0; j < smd->verts[i].binds_num; j++) {
1693 reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
1694
1696 {
1697 BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
1698 }
1699 else {
1701 reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_weights);
1702 }
1703 }
1704 }
1705 }
1706 }
1707}
1708
1710 /*idname*/ "SurfaceDeform",
1711 /*name*/ N_("SurfaceDeform"),
1712 /*struct_name*/ "SurfaceDeformModifierData",
1713 /*struct_size*/ sizeof(SurfaceDeformModifierData),
1714 /*srna*/ &RNA_SurfaceDeformModifier,
1717 /*icon*/ ICON_MOD_MESHDEFORM,
1718
1719 /*copy_data*/ copy_data,
1720
1721 /*deform_verts*/ deform_verts,
1722 /*deform_matrices*/ nullptr,
1723 /*deform_verts_EM*/ nullptr,
1724 /*deform_matrices_EM*/ nullptr,
1725 /*modify_mesh*/ nullptr,
1726 /*modify_geometry_set*/ nullptr,
1727
1728 /*init_data*/ init_data,
1729 /*required_data_mask*/ required_data_mask,
1730 /*free_data*/ free_data,
1731 /*is_disabled*/ is_disabled,
1732 /*update_depsgraph*/ update_depsgraph,
1733 /*depends_on_time*/ nullptr,
1734 /*depends_on_normals*/ nullptr,
1735 /*foreach_ID_link*/ foreach_ID_link,
1736 /*foreach_tex_link*/ nullptr,
1737 /*free_runtime_data*/ nullptr,
1738 /*panel_register*/ panel_register,
1739 /*blend_write*/ blend_write,
1740 /*blend_read*/ blend_read,
1741 /*foreach_cache*/ nullptr,
1742};
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
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
@ IDWALK_NOP
int BKE_mesh_wrapper_vert_len(const Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *mesh, float(*vert_coords)[3], int vert_coords_len, const float mat[4][4])
int BKE_mesh_wrapper_face_len(const Mesh *mesh)
Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
ModifierData * BKE_modifier_get_original(const Object *object, ModifierData *md)
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
void void BKE_modifier_set_warning(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_PI_2
MINLINE float interpf(float target, float origin, float t)
MINLINE float signf(float f)
#define M_PI
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:517
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
bool isect_point_poly_v2(const float pt[2], const float verts[][2], unsigned int nr)
void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], float angle)
void interp_weights_poly_v2(float w[], float v[][2], int n, const float co[2])
bool isect_line_plane_v3(float r_isect_co[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr)
Definition math_geom.cc:77
bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:284
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f)
void mid_v3_v3_array(float r[3], const float(*vec_arr)[3], unsigned int vec_arr_num)
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float n[2])
MINLINE void zero_v3(float r[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4977
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr)
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4967
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
Definition readfile.cc:4957
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define IFACE_(msgid)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
@ eModifierFlag_OverrideLibrary_Local
struct SurfaceDeformModifierData SurfaceDeformModifierData
@ MOD_SDEF_MODE_CENTROID
@ MOD_SDEF_MODE_NGONS
@ MOD_SDEF_MODE_CORNER_TRIS
@ eModifierType_SurfaceDeform
@ MOD_SDEF_BIND
@ MOD_SDEF_INVERT_VGROUP
@ MOD_SDEF_SPARSE_BIND
Object is a sort of wrapper for general info.
@ OB_MESH
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
static bool is_disabled
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void init_data(ModifierData *md)
BLI_INLINE SDefBindWeightData * computeBindWeights(SDefBindCalcData *const data, const float point_co[3])
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges, SDefAdjacency *const adj_ref, SDefEdgePolys *const edge_polys)
BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3])
static void freeBindData(SDefBindWeightData *const bwdata)
static void panel_register(ARegionType *region_type)
BLI_INLINE int isPolyValid(const float coords[][2], const uint nr)
BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle)
static void surfacedeformModifier_do(ModifierData *md, const ModifierEvalContext *ctx, float(*vertexCos)[3], uint verts_num, Object *ob, Mesh *mesh)
@ MOD_SDEF_INFINITE_WEIGHT_DIST
@ MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ
@ MOD_SDEF_INFINITE_WEIGHT_ANGULAR
static void bindVert(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
static void free_data(ModifierData *md)
static int buildAdjacencyMap(const blender::OffsetIndices< int > polys, const blender::Span< blender::int2 > edges, const blender::Span< int > corner_edges, SDefAdjacencyArray *const vert_edges, SDefAdjacency *adj, SDefEdgePolys *const edge_polys)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void compactSparseBinds(SurfaceDeformModifierData *smd)
static bool surfacedeformBind(Object *ob, SurfaceDeformModifierData *smd_orig, SurfaceDeformModifierData *smd_eval, float(*vertexCos)[3], uint verts_num, uint target_faces_num, uint target_verts_num, Mesh *target, Mesh *mesh)
static void panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
BLI_INLINE void sortPolyVertsEdge(uint *indices, const int *const corner_verts, const int *const corner_edges, const uint edge, const uint num)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
BLI_INLINE void sortPolyVertsTri(uint *indices, const int *const corner_verts, const uint loopstart, const uint num)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
BLI_INLINE float computeNormalDisplacement(const float point_co[3], const float point_co_proj[3], const float normal[3])
@ MOD_SDEF_BIND_RESULT_SUCCESS
@ MOD_SDEF_BIND_RESULT_CONCAVE_ERR
@ MOD_SDEF_BIND_RESULT_MEM_ERR
@ MOD_SDEF_BIND_RESULT_GENERIC_ERR
@ MOD_SDEF_BIND_RESULT_OVERLAP_ERR
@ MOD_SDEF_BIND_RESULT_NONMANY_ERR
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void deformVert(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
ModifierTypeInfo modifierType_SurfaceDeform
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:159
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
#define UI_ITEM_NONE
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
const T * data() const
Definition BLI_array.hh:301
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
#define sinf(x)
#define powf(x, y)
#define fabsf(x)
#define sqrtf(x)
draw_view in_light_buf[] float
uint col
void *(* MEM_reallocN_id)(void *vmemh, size_t len, const char *str)
Definition mallocn.cc:40
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
int RNA_string_length(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:413
struct uiLayout * layout
SDefAdjacency * first
SDefAdjacency * next
const float(* vertexCos)[3]
blender::Span< int > tri_faces
const SDefEdgePolys * edge_polys
blender::Span< blender::int2 > edges
blender::OffsetIndices< int > polys
blender::Span< blender::int3 > corner_tris
const SDefAdjacencyArray * vert_edges
BVHTreeFromMesh * treeData
blender::Span< int > corner_edges
blender::Span< int > corner_verts
const MDeformVert * dvert
float corner_edgemid_angles[2]
float cent_edgemid_vecs_v2[2][2]
float point_edgemid_angles[2]
float(* coords_v2)[2]
float(* coords)[3]
SDefBindPoly * bind_polys
unsigned int verts_num
unsigned int * vert_inds
const SDefVert * bind_verts
const MDeformVert * dvert
unsigned int binds_num
SDefBind * binds
unsigned int vertex_idx
ccl_device_inline float sqr(float a)
Definition util/math.h:782
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138