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