Blender V4.5
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
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 *>(
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_CB_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 = MEM_callocN<SDefBindWeightData>("SDefBindWeightData");
492 if (bwdata == nullptr) {
494 return nullptr;
495 }
496
497 bwdata->faces_num = data->vert_edges[nearest].num / 2;
498
499 bpoly = MEM_calloc_arrayN<SDefBindPoly>(bwdata->faces_num, "SDefBindPoly");
500 if (bpoly == nullptr) {
501 freeBindData(bwdata);
503 return nullptr;
504 }
505
506 bwdata->bind_polys = bpoly;
507
508 /* Loop over all adjacent edges,
509 * and build the #SDefBindPoly data for each face adjacent to those. */
510 for (vedge = vert_edges; vedge; vedge = vedge->next) {
511 uint edge_ind = vedge->index;
512
513 for (int i = 0; i < edge_polys[edge_ind].num; i++) {
514 {
515 bpoly = bwdata->bind_polys;
516
517 for (int j = 0; j < bwdata->faces_num; bpoly++, j++) {
518 /* If coords isn't allocated, we have reached the first uninitialized `bpoly`. */
519 if ((bpoly->index == edge_polys[edge_ind].polys[i]) || (!bpoly->coords)) {
520 break;
521 }
522 }
523 }
524
525 /* Check if face was already created by another edge or still has to be initialized */
526 if (!bpoly->coords) {
527 float angle;
528 float axis[3];
529 float tmp_vec_v2[2];
530 int is_poly_valid;
531
532 bpoly->index = edge_polys[edge_ind].polys[i];
533 bpoly->coords = nullptr;
534 bpoly->coords_v2 = nullptr;
535
536 /* Copy face data */
537 const blender::IndexRange face = data->polys[bpoly->index];
538
539 bpoly->verts_num = face.size();
540 bpoly->loopstart = face.start();
541
542 bpoly->coords = MEM_malloc_arrayN<float[3]>(size_t(face.size()), "SDefBindPolyCoords");
543 if (bpoly->coords == nullptr) {
544 freeBindData(bwdata);
546 return nullptr;
547 }
548
549 bpoly->coords_v2 = MEM_malloc_arrayN<float[2]>(size_t(face.size()),
550 "SDefBindPolyCoords_v2");
551 if (bpoly->coords_v2 == nullptr) {
552 freeBindData(bwdata);
554 return nullptr;
555 }
556
557 for (int j = 0; j < face.size(); j++) {
558 const int vert_i = data->corner_verts[face.start() + j];
559 const int edge_i = data->corner_edges[face.start() + j];
560 copy_v3_v3(bpoly->coords[j], data->targetCos[vert_i]);
561
562 /* Find corner and edge indices within face loop array */
563 if (vert_i == nearest) {
564 bpoly->corner_ind = j;
565 bpoly->edge_vert_inds[0] = (j == 0) ? (face.size() - 1) : (j - 1);
566 bpoly->edge_vert_inds[1] = (j == face.size() - 1) ? (0) : (j + 1);
567
568 bpoly->edge_inds[0] = data->corner_edges[face.start() + bpoly->edge_vert_inds[0]];
569 bpoly->edge_inds[1] = edge_i;
570 }
571 }
572
573 /* Compute polygons parametric data. */
574 mid_v3_v3_array(bpoly->centroid, bpoly->coords, face.size());
575 normal_poly_v3(bpoly->normal, bpoly->coords, face.size());
576
577 /* Compute face skew angle and axis */
578 angle = angle_normalized_v3v3(bpoly->normal, world);
579
580 cross_v3_v3v3(axis, bpoly->normal, world);
581 normalize_v3(axis);
582
583 /* Map coords onto 2d normal plane. */
584 map_to_plane_axis_angle_v2_v3v3fl(bpoly->point_v2, point_co, axis, angle);
585
586 zero_v2(bpoly->centroid_v2);
587 for (int j = 0; j < face.size(); j++) {
588 map_to_plane_axis_angle_v2_v3v3fl(bpoly->coords_v2[j], bpoly->coords[j], axis, angle);
589 madd_v2_v2fl(bpoly->centroid_v2, bpoly->coords_v2[j], 1.0f / face.size());
590 }
591
592 is_poly_valid = isPolyValid(bpoly->coords_v2, face.size());
593
594 if (is_poly_valid != MOD_SDEF_BIND_RESULT_SUCCESS) {
595 freeBindData(bwdata);
596 data->success = is_poly_valid;
597 return nullptr;
598 }
599
600 bpoly->inside = isect_point_poly_v2(bpoly->point_v2, bpoly->coords_v2, face.size());
601
602 /* Initialize weight components */
603 bpoly->weight_angular = 1.0f;
604 bpoly->weight_dist_proj = len_v2v2(bpoly->centroid_v2, bpoly->point_v2);
605 bpoly->weight_dist = len_v3v3(bpoly->centroid, point_co);
606
607 avg_point_dist += bpoly->weight_dist;
608
609 /* Common vertex coordinates. */
610 const float *const vert0_v2 = bpoly->coords_v2[bpoly->edge_vert_inds[0]];
611 const float *const vert1_v2 = bpoly->coords_v2[bpoly->edge_vert_inds[1]];
612 const float *const corner_v2 = bpoly->coords_v2[bpoly->corner_ind];
613
614 /* Compute centroid to mid-edge vectors */
615 mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0], vert0_v2, corner_v2);
616 mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1], vert1_v2, corner_v2);
617
618 sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2);
619 sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2);
620
623
624 /* Compute face scales with respect to the two edges. */
625 bpoly->scales[0] = dist_to_line_v2(bpoly->centroid_v2, vert0_v2, corner_v2);
626 bpoly->scales[1] = dist_to_line_v2(bpoly->centroid_v2, vert1_v2, corner_v2);
627
628 /* Compute the angle between the edge mid vectors. */
630 bpoly->cent_edgemid_vecs_v2[1]);
631
632 /* Compute the angles between the corner and the edge mid vectors. The angles
633 * are computed signed in order to correctly clamp point_edgemid_angles later. */
634 float corner_angles[2];
635
636 sub_v2_v2v2(tmp_vec_v2, corner_v2, bpoly->centroid_v2);
637 normalize_v2(tmp_vec_v2);
638
639 corner_angles[0] = angle_signed_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[0]);
640 corner_angles[1] = angle_signed_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[1]);
641
642 bpoly->corner_edgemid_angles[0] = fabsf(corner_angles[0]);
643 bpoly->corner_edgemid_angles[1] = fabsf(corner_angles[1]);
644
645 /* Verify that the computed values are valid (the face isn't somehow
646 * degenerate despite having passed isPolyValid). */
647 if (bpoly->scales[0] < FLT_EPSILON || bpoly->scales[1] < FLT_EPSILON ||
648 bpoly->edgemid_angle < FLT_EPSILON || bpoly->corner_edgemid_angles[0] < FLT_EPSILON ||
649 bpoly->corner_edgemid_angles[1] < FLT_EPSILON)
650 {
651 freeBindData(bwdata);
653 return nullptr;
654 }
655
656 /* Check for infinite weights, and compute angular data otherwise. */
657 if (bpoly->weight_dist < FLT_EPSILON) {
658 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
659 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
660 }
661 else if (bpoly->weight_dist_proj < FLT_EPSILON) {
662 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
663 }
664 else {
665 /* Compute angles between the point and the edge mid vectors. */
666 float cent_point_vec[2], point_angles[2];
667
668 sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2);
669 normalize_v2(cent_point_vec);
670
671 point_angles[0] = angle_signed_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[0]) *
672 signf(corner_angles[0]);
673 point_angles[1] = angle_signed_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[1]) *
674 signf(corner_angles[1]);
675
676 if (point_angles[0] <= 0 && point_angles[1] <= 0) {
677 /* If the point is outside the corner formed by the edge mid vectors,
678 * choose to clamp the closest side and flip the other. */
679 if (point_angles[0] < point_angles[1]) {
680 point_angles[0] = bpoly->edgemid_angle - point_angles[1];
681 }
682 else {
683 point_angles[1] = bpoly->edgemid_angle - point_angles[0];
684 }
685 }
686
687 bpoly->point_edgemid_angles[0] = max_ff(0, point_angles[0]);
688 bpoly->point_edgemid_angles[1] = max_ff(0, point_angles[1]);
689
690 /* Compute the distance scale for the corner. The base value is the orthogonal
691 * distance from the corner to the chord, scaled by `sqrt(2)` to preserve the old
692 * values in case of a square grid. This doesn't use the centroid because the
693 * corner_triS method only uses these three vertices. */
694 bpoly->scale_mid = area_tri_v2(vert0_v2, corner_v2, vert1_v2) /
695 len_v2v2(vert0_v2, vert1_v2) * sqrtf(2);
696
697 if (bpoly->inside) {
698 /* When inside, interpolate to centroid-based scale close to the center. */
699 float min_dist = min_ff(bpoly->scales[0], bpoly->scales[1]);
700
701 bpoly->scale_mid = interpf(bpoly->scale_mid,
702 (bpoly->scales[0] + bpoly->scales[1]) / 2,
703 min_ff(bpoly->weight_dist_proj / min_dist, 1));
704 }
705
706 /* Verify that the additional computed values are valid. */
707 if (bpoly->scale_mid < FLT_EPSILON ||
708 bpoly->point_edgemid_angles[0] + bpoly->point_edgemid_angles[1] < FLT_EPSILON)
709 {
710 freeBindData(bwdata);
712 return nullptr;
713 }
714 }
715 }
716 }
717 }
718
719 avg_point_dist /= bwdata->faces_num;
720
721 /* If weights 1 and 2 are not infinite, loop over all adjacent edges again,
722 * and build adjacency dependent angle data (depends on all polygons having been computed) */
723 if (!inf_weight_flags) {
724 for (vedge = vert_edges; vedge; vedge = vedge->next) {
725 SDefBindPoly *bpolys[2];
726 const SDefEdgePolys *epolys;
727 float ang_weights[2];
728 uint edge_ind = vedge->index;
729 uint edge_on_poly[2];
730
731 epolys = &edge_polys[edge_ind];
732
733 /* Find bind polys corresponding to the edge's adjacent polys */
734 bpoly = bwdata->bind_polys;
735
736 for (int i = 0, j = 0; (i < bwdata->faces_num) && (j < epolys->num); bpoly++, i++) {
737 if (ELEM(bpoly->index, epolys->polys[0], epolys->polys[1])) {
738 bpolys[j] = bpoly;
739
740 if (bpoly->edge_inds[0] == edge_ind) {
741 edge_on_poly[j] = 0;
742 }
743 else {
744 edge_on_poly[j] = 1;
745 }
746
747 j++;
748 }
749 }
750
751 /* Compute angular weight component */
752 if (epolys->num == 1) {
753 ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
754 bpolys[0]->edgemid_angle);
755 bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0];
756 }
757 else if (epolys->num == 2) {
758 ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
759 bpolys[0]->edgemid_angle);
760 ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]],
761 bpolys[1]->edgemid_angle);
762
763 bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1];
764 bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1];
765 }
766 }
767 }
768
769 /* Compute scaling and falloff:
770 * - Scale all weights if no infinite weight is found.
771 * - Scale only un-projected weight if projected weight is infinite.
772 * - Scale none if both are infinite. */
773 if (!inf_weight_flags) {
774 bpoly = bwdata->bind_polys;
775
776 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
777 float corner_angle_weights[2];
778 float scale_weight, sqr, inv_sqr;
779
780 corner_angle_weights[0] = bpoly->point_edgemid_angles[0] / bpoly->corner_edgemid_angles[0];
781 corner_angle_weights[1] = bpoly->point_edgemid_angles[1] / bpoly->corner_edgemid_angles[1];
782
783 if (isnan(corner_angle_weights[0]) || isnan(corner_angle_weights[1])) {
784 freeBindData(bwdata);
786 return nullptr;
787 }
788
789 /* Find which edge the point is closer to */
790 if (corner_angle_weights[0] < corner_angle_weights[1]) {
791 bpoly->dominant_edge = 0;
792 bpoly->dominant_angle_weight = corner_angle_weights[0];
793 }
794 else {
795 bpoly->dominant_edge = 1;
796 bpoly->dominant_angle_weight = corner_angle_weights[1];
797 }
798
799 /* Check for invalid weights just in case computations fail. */
800 if (bpoly->dominant_angle_weight < 0 || bpoly->dominant_angle_weight > 1) {
801 freeBindData(bwdata);
803 return nullptr;
804 }
805
807
808 /* Compute quadratic angular scale interpolation weight */
809 {
810 const float edge_angle_a = bpoly->point_edgemid_angles[bpoly->dominant_edge];
811 const float edge_angle_b = bpoly->point_edgemid_angles[!bpoly->dominant_edge];
812 /* Clamp so skinny faces with near zero `edgemid_angle`
813 * won't cause numeric problems. see #81988. */
814 scale_weight = edge_angle_a / max_ff(edge_angle_a, bpoly->edgemid_angle);
815 scale_weight /= scale_weight + (edge_angle_b / max_ff(edge_angle_b, bpoly->edgemid_angle));
816 }
817
818 sqr = scale_weight * scale_weight;
819 inv_sqr = 1.0f - scale_weight;
820 inv_sqr *= inv_sqr;
821 scale_weight = sqr / (sqr + inv_sqr);
822
823 BLI_assert(scale_weight >= 0 && scale_weight <= 1);
824
825 /* Compute interpolated scale (no longer need the individual scales,
826 * so simply storing the result over the scale in index zero) */
827 bpoly->scales[0] = interpf(bpoly->scale_mid,
828 interpf(bpoly->scales[!bpoly->dominant_edge],
829 bpoly->scales[bpoly->dominant_edge],
830 scale_weight),
831 bpoly->dominant_angle_weight);
832
833 /* Scale the point distance weights, and introduce falloff */
834 bpoly->weight_dist_proj /= bpoly->scales[0];
835 bpoly->weight_dist_proj = powf(bpoly->weight_dist_proj, data->falloff);
836
837 bpoly->weight_dist /= avg_point_dist;
838 bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
839
840 /* Re-check for infinite weights, now that all scalings and interpolations are computed */
841 if (bpoly->weight_dist < FLT_EPSILON) {
842 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
843 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
844 }
845 else if (bpoly->weight_dist_proj < FLT_EPSILON) {
846 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
847 }
848 else if (bpoly->weight_angular < FLT_EPSILON) {
849 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_ANGULAR;
850 }
851 }
852 }
853 else if (!(inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST)) {
854 bpoly = bwdata->bind_polys;
855
856 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
857 /* Scale the point distance weight by average point distance, and introduce falloff */
858 bpoly->weight_dist /= avg_point_dist;
859 bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
860
861 /* Re-check for infinite weights, now that all scalings and interpolations are computed */
862 if (bpoly->weight_dist < FLT_EPSILON) {
863 inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
864 }
865 }
866 }
867
868 /* Final loop, to compute actual weights */
869 bpoly = bwdata->bind_polys;
870
871 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
872 /* Weight computation from components */
873 if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST) {
874 bpoly->weight = bpoly->weight_dist < FLT_EPSILON ? 1.0f : 0.0f;
875 }
876 else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ) {
877 bpoly->weight = bpoly->weight_dist_proj < FLT_EPSILON ? 1.0f / bpoly->weight_dist : 0.0f;
878 }
879 else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_ANGULAR) {
880 bpoly->weight = bpoly->weight_angular < FLT_EPSILON ?
881 1.0f / bpoly->weight_dist_proj / bpoly->weight_dist :
882 0.0f;
883 }
884 else {
885 bpoly->weight = 1.0f / bpoly->weight_angular / bpoly->weight_dist_proj / bpoly->weight_dist;
886 }
887
888 /* Apply after other kinds of scaling so the faces corner angle is always
889 * scaled in a uniform way, preventing heavily sub-divided triangle fans
890 * from having a lop-sided influence on the weighting, see #81988. */
891 bpoly->weight *= bpoly->edgemid_angle / M_PI;
892
893 tot_weight += bpoly->weight;
894 }
895
896 bpoly = bwdata->bind_polys;
897
898 for (int i = 0; i < bwdata->faces_num; bpoly++, i++) {
899 bpoly->weight /= tot_weight;
900
901 /* Evaluate if this face is relevant to bind */
902 /* Even though the weights should add up to 1.0,
903 * the losses of weights smaller than epsilon here
904 * should be negligible... */
905 if (bpoly->weight >= FLT_EPSILON) {
906 if (bpoly->inside) {
907 bwdata->binds_num += 1;
908 }
909 else {
910 if (bpoly->dominant_angle_weight < FLT_EPSILON ||
911 1.0f - bpoly->dominant_angle_weight < FLT_EPSILON)
912 {
913 bwdata->binds_num += 1;
914 }
915 else {
916 bwdata->binds_num += 2;
917 }
918 }
919 }
920 }
921
922 return bwdata;
923}
924
925BLI_INLINE float computeNormalDisplacement(const float point_co[3],
926 const float point_co_proj[3],
927 const float normal[3])
928{
929 float disp_vec[3];
930 float normal_dist;
931
932 sub_v3_v3v3(disp_vec, point_co, point_co_proj);
933 normal_dist = len_v3(disp_vec);
934
935 if (dot_v3v3(disp_vec, normal) < 0) {
936 normal_dist *= -1;
937 }
938
939 return normal_dist;
940}
941
942static void bindVert(void *__restrict userdata,
943 const int index,
944 const TaskParallelTLS *__restrict /*tls*/)
945{
946 SDefBindCalcData *const data = (SDefBindCalcData *)userdata;
947 float point_co[3];
948 float point_co_proj[3];
949
950 SDefBindWeightData *bwdata;
951 SDefVert *sdvert = data->bind_verts + index;
952 SDefBindPoly *bpoly;
953 SDefBind *sdbind;
954
955 sdvert->vertex_idx = index;
956
957 if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) {
958 sdvert->binds = nullptr;
959 sdvert->binds_num = 0;
960 return;
961 }
962
963 if (data->sparse_bind) {
964 float weight = 0.0f;
965
966 if (data->dvert && data->defgrp_index != -1) {
967 weight = BKE_defvert_find_weight(&data->dvert[index], data->defgrp_index);
968 }
969
970 if (data->invert_vgroup) {
971 weight = 1.0f - weight;
972 }
973
974 if (weight <= 0) {
975 sdvert->binds = nullptr;
976 sdvert->binds_num = 0;
977 return;
978 }
979 }
980
981 copy_v3_v3(point_co, data->vertexCos[index]);
982 bwdata = computeBindWeights(data, point_co);
983
984 if (bwdata == nullptr) {
985 sdvert->binds = nullptr;
986 sdvert->binds_num = 0;
987 return;
988 }
989
990 sdvert->binds = MEM_calloc_arrayN<SDefBind>(bwdata->binds_num, "SDefVertBindData");
991 if (sdvert->binds == nullptr) {
993 sdvert->binds_num = 0;
994 return;
995 }
996
997 sdvert->binds_num = bwdata->binds_num;
998
999 sdbind = sdvert->binds;
1000
1001 bpoly = bwdata->bind_polys;
1002
1003 for (int i = 0; i < bwdata->binds_num; bpoly++) {
1004 if (bpoly->weight >= FLT_EPSILON) {
1005 if (bpoly->inside) {
1006 sdbind->influence = bpoly->weight;
1007 sdbind->verts_num = bpoly->verts_num;
1008
1009 sdbind->mode = MOD_SDEF_MODE_NGONS;
1010 sdbind->vert_weights = MEM_malloc_arrayN<float>(size_t(bpoly->verts_num),
1011 "SDefNgonVertWeights");
1012 if (sdbind->vert_weights == nullptr) {
1014 return;
1015 }
1016
1017 sdbind->vert_inds = MEM_malloc_arrayN<uint>(size_t(bpoly->verts_num), "SDefNgonVertInds");
1018 if (sdbind->vert_inds == nullptr) {
1020 return;
1021 }
1022
1024 sdbind->vert_weights, bpoly->coords_v2, bpoly->verts_num, bpoly->point_v2);
1025
1026 /* Re-project vert based on weights and original face verts,
1027 * to reintroduce face non-planarity */
1028 zero_v3(point_co_proj);
1029 for (int j = 0; j < bpoly->verts_num; j++) {
1030 const int vert_i = data->corner_verts[bpoly->loopstart + j];
1031 madd_v3_v3fl(point_co_proj, bpoly->coords[j], sdbind->vert_weights[j]);
1032 sdbind->vert_inds[j] = vert_i;
1033 }
1034
1035 sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
1036
1037 sdbind++;
1038 i++;
1039 }
1040 else {
1041 float tmp_vec[3];
1042 float cent[3], norm[3];
1043 float v1[3], v2[3], v3[3];
1044
1045 if (1.0f - bpoly->dominant_angle_weight >= FLT_EPSILON) {
1046 sdbind->influence = bpoly->weight * (1.0f - bpoly->dominant_angle_weight);
1047 sdbind->verts_num = bpoly->verts_num;
1048
1049 sdbind->mode = MOD_SDEF_MODE_CENTROID;
1050 sdbind->vert_weights = MEM_malloc_arrayN<float>(3, "SDefCentVertWeights");
1051 if (sdbind->vert_weights == nullptr) {
1053 return;
1054 }
1055
1056 sdbind->vert_inds = MEM_malloc_arrayN<uint>(size_t(bpoly->verts_num),
1057 "SDefCentVertInds");
1058 if (sdbind->vert_inds == nullptr) {
1060 return;
1061 }
1062
1064 &data->corner_verts[bpoly->loopstart],
1065 &data->corner_edges[bpoly->loopstart],
1066 bpoly->edge_inds[bpoly->dominant_edge],
1067 bpoly->verts_num);
1068
1069 copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
1070 copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
1071 copy_v3_v3(v3, bpoly->centroid);
1072
1073 mid_v3_v3v3v3(cent, v1, v2, v3);
1074 normal_tri_v3(norm, v1, v2, v3);
1075
1076 add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
1077
1078 /* We are sure the line is not parallel to the plane.
1079 * Checking return value just to avoid warning... */
1080 if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
1081 BLI_assert(false);
1082 }
1083
1084 interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
1085
1086 sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
1087
1088 sdbind++;
1089 i++;
1090 }
1091
1092 if (bpoly->dominant_angle_weight >= FLT_EPSILON) {
1093 sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight;
1094 sdbind->verts_num = bpoly->verts_num;
1095
1097 sdbind->vert_weights = MEM_malloc_arrayN<float>(3, "SDefTriVertWeights");
1098 if (sdbind->vert_weights == nullptr) {
1100 return;
1101 }
1102
1103 sdbind->vert_inds = MEM_malloc_arrayN<uint>(size_t(bpoly->verts_num), "SDefTriVertInds");
1104 if (sdbind->vert_inds == nullptr) {
1106 return;
1107 }
1108
1110 &data->corner_verts[bpoly->loopstart],
1111 bpoly->edge_vert_inds[0],
1112 bpoly->verts_num);
1113
1114 copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
1115 copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
1116 copy_v3_v3(v3, data->targetCos[sdbind->vert_inds[2]]);
1117
1118 mid_v3_v3v3v3(cent, v1, v2, v3);
1119 normal_tri_v3(norm, v1, v2, v3);
1120
1121 add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
1122
1123 /* We are sure the line is not parallel to the plane.
1124 * Checking return value just to avoid warning... */
1125 if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
1126 BLI_assert(false);
1127 }
1128
1129 interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
1130
1131 sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
1132
1133 sdbind++;
1134 i++;
1135 }
1136 }
1137 }
1138 }
1139
1140 freeBindData(bwdata);
1141}
1142
1143/* Remove vertices without bind data from the bind array. */
1145{
1146 smd->bind_verts_num = 0;
1147
1148 for (uint i = 0; i < smd->mesh_verts_num; i++) {
1149 if (smd->verts[i].binds_num > 0) {
1150 smd->verts[smd->bind_verts_num++] = smd->verts[i];
1151 }
1152 }
1153
1154 smd->verts = static_cast<SDefVert *>(MEM_reallocN_id(
1155 smd->verts, sizeof(*smd->verts) * smd->bind_verts_num, "SDefBindVerts (sparse)"));
1156}
1157
1159 SurfaceDeformModifierData *smd_orig,
1160 SurfaceDeformModifierData *smd_eval,
1161 float (*vertexCos)[3],
1162 uint verts_num,
1163 uint target_faces_num,
1164 uint target_verts_num,
1165 Mesh *target,
1166 Mesh *mesh)
1167{
1168 const blender::Span<blender::float3> positions = target->vert_positions();
1169 const blender::Span<blender::int2> edges = target->edges();
1170 const blender::OffsetIndices polys = target->faces();
1171 const blender::Span<int> corner_verts = target->corner_verts();
1172 const blender::Span<int> corner_edges = target->corner_edges();
1173 uint tedges_num = target->edges_num;
1174 int adj_result;
1175
1176 SDefAdjacencyArray *vert_edges = MEM_calloc_arrayN<SDefAdjacencyArray>(target_verts_num,
1177 "SDefVertEdgeMap");
1178 if (vert_edges == nullptr) {
1179 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1180 return false;
1181 }
1182
1183 SDefAdjacency *adj_array = MEM_malloc_arrayN<SDefAdjacency>(2 * size_t(tedges_num),
1184 "SDefVertEdge");
1185 if (adj_array == nullptr) {
1186 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1187 MEM_freeN(vert_edges);
1188 return false;
1189 }
1190
1191 SDefEdgePolys *edge_polys = MEM_calloc_arrayN<SDefEdgePolys>(tedges_num, "SDefEdgeFaceMap");
1192 if (edge_polys == nullptr) {
1193 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1194 MEM_freeN(vert_edges);
1195 MEM_freeN(adj_array);
1196 return false;
1197 }
1198
1199 smd_orig->verts = MEM_malloc_arrayN<SDefVert>(size_t(verts_num), "SDefBindVerts");
1200 if (smd_orig->verts == nullptr) {
1201 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1202 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1203 return false;
1204 }
1205
1206 blender::bke::BVHTreeFromMesh treeData = target->bvh_corner_tris();
1207 if (treeData.tree == nullptr) {
1208 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1209 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1210 MEM_freeN(smd_orig->verts);
1211 smd_orig->verts = nullptr;
1212 return false;
1213 }
1214
1215 adj_result = buildAdjacencyMap(polys, edges, corner_edges, vert_edges, adj_array, edge_polys);
1216
1217 if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
1219 ob, (ModifierData *)smd_eval, "Target has edges with more than two polygons");
1220 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1221 MEM_freeN(smd_orig->verts);
1222 smd_orig->verts = nullptr;
1223 return false;
1224 }
1225
1226 smd_orig->mesh_verts_num = verts_num;
1227 smd_orig->target_verts_num = target_verts_num;
1228 smd_orig->target_polys_num = target_faces_num;
1229
1230 int defgrp_index;
1231 const MDeformVert *dvert;
1232 MOD_get_vgroup(ob, mesh, smd_orig->defgrp_name, &dvert, &defgrp_index);
1233 const bool invert_vgroup = (smd_orig->flags & MOD_SDEF_INVERT_VGROUP) != 0;
1234 const bool sparse_bind = (smd_orig->flags & MOD_SDEF_SPARSE_BIND) != 0;
1235
1237 data.treeData = &treeData;
1238 data.vert_edges = vert_edges;
1239 data.edge_polys = edge_polys;
1240 data.polys = polys;
1241 data.edges = edges;
1242 data.corner_verts = corner_verts;
1243 data.corner_edges = corner_edges;
1244 data.corner_tris = target->corner_tris();
1245 data.tri_faces = target->corner_tri_faces();
1246 data.targetCos = MEM_malloc_arrayN<float[3]>(size_t(target_verts_num),
1247 "SDefTargetBindVertArray");
1248 data.bind_verts = smd_orig->verts;
1249 data.vertexCos = vertexCos;
1250 data.falloff = smd_orig->falloff;
1252 data.dvert = dvert;
1253 data.defgrp_index = defgrp_index;
1254 data.invert_vgroup = invert_vgroup;
1255 data.sparse_bind = sparse_bind;
1256
1257 if (data.targetCos == nullptr) {
1258 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1259 free_data((ModifierData *)smd_orig);
1260 return false;
1261 }
1262
1263 invert_m4_m4(data.imat, smd_orig->mat);
1264
1265 for (int i = 0; i < target_verts_num; i++) {
1266 mul_v3_m4v3(data.targetCos[i], smd_orig->mat, positions[i]);
1267 }
1268
1269 TaskParallelSettings settings;
1271 settings.use_threading = (verts_num > 10000);
1272 BLI_task_parallel_range(0, verts_num, &data, bindVert, &settings);
1273
1274 MEM_freeN(data.targetCos);
1275
1276 if (sparse_bind) {
1277 compactSparseBinds(smd_orig);
1278 }
1279 else {
1280 smd_orig->bind_verts_num = verts_num;
1281 }
1282
1283 if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
1284 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
1285 free_data((ModifierData *)smd_orig);
1286 }
1287 else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
1289 ob, (ModifierData *)smd_eval, "Target has edges with more than two polygons");
1290 free_data((ModifierData *)smd_orig);
1291 }
1292 else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) {
1293 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains concave polygons");
1294 free_data((ModifierData *)smd_orig);
1295 }
1296 else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) {
1297 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains overlapping vertices");
1298 free_data((ModifierData *)smd_orig);
1299 }
1300 else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) {
1301 /* I know this message is vague, but I could not think of a way
1302 * to explain this with a reasonably sized message.
1303 * Though it shouldn't really matter all that much,
1304 * because this is very unlikely to occur */
1305 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Target contains invalid polygons");
1306 free_data((ModifierData *)smd_orig);
1307 }
1308 else if (smd_orig->bind_verts_num == 0 || !smd_orig->verts) {
1310 BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "No vertices were bound");
1311 free_data((ModifierData *)smd_orig);
1312 }
1313
1314 freeAdjacencyMap(vert_edges, adj_array, edge_polys);
1315
1316 return data.success == 1;
1317}
1318
1319static void deformVert(void *__restrict userdata,
1320 const int index,
1321 const TaskParallelTLS *__restrict /*tls*/)
1322{
1323 const SDefDeformData *const data = (SDefDeformData *)userdata;
1324 const SDefBind *sdbind = data->bind_verts[index].binds;
1325 const int sdbind_num = data->bind_verts[index].binds_num;
1326 const uint vertex_idx = data->bind_verts[index].vertex_idx;
1327 float *const vertexCos = data->vertexCos[vertex_idx];
1328 float norm[3], temp[3], offset[3];
1329
1330 /* Retrieve the value of the weight vertex group if specified. */
1331 float weight = 1.0f;
1332
1333 if (data->dvert && data->defgrp_index != -1) {
1334 weight = BKE_defvert_find_weight(&data->dvert[vertex_idx], data->defgrp_index);
1335
1336 if (data->invert_vgroup) {
1337 weight = 1.0f - weight;
1338 }
1339 }
1340
1341 /* Check if this vertex will be deformed. If it is not deformed we return and avoid
1342 * unnecessary calculations. */
1343 if (weight == 0.0f) {
1344 return;
1345 }
1346
1347 zero_v3(offset);
1348
1349 int max_verts = 0;
1350 for (int j = 0; j < sdbind_num; j++) {
1351 max_verts = std::max(max_verts, int(sdbind[j].verts_num));
1352 }
1353
1354 /* Allocate a `coords_buffer` that fits all the temp-data. */
1355 blender::Array<blender::float3, 256> coords_buffer(max_verts);
1356
1357 for (int j = 0; j < sdbind_num; j++, sdbind++) {
1358 for (int k = 0; k < sdbind->verts_num; k++) {
1359 copy_v3_v3(coords_buffer[k], data->targetCos[sdbind->vert_inds[k]]);
1360 }
1361
1363 norm, reinterpret_cast<const float(*)[3]>(coords_buffer.data()), sdbind->verts_num);
1364 zero_v3(temp);
1365
1366 switch (sdbind->mode) {
1367 /* ---------- corner_tri mode ---------- */
1369 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
1370 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
1371 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]);
1372 break;
1373 }
1374
1375 /* ---------- ngon mode ---------- */
1376 case MOD_SDEF_MODE_NGONS: {
1377 for (int k = 0; k < sdbind->verts_num; k++) {
1378 madd_v3_v3fl(temp, coords_buffer[k], sdbind->vert_weights[k]);
1379 }
1380 break;
1381 }
1382
1383 /* ---------- centroid mode ---------- */
1385 float cent[3];
1387 cent, reinterpret_cast<const float(*)[3]>(coords_buffer.data()), sdbind->verts_num);
1388
1389 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
1390 madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
1391 madd_v3_v3fl(temp, cent, sdbind->vert_weights[2]);
1392 break;
1393 }
1394 }
1395
1396 /* Apply normal offset (generic for all modes) */
1397 madd_v3_v3fl(temp, norm, sdbind->normal_dist);
1398
1399 madd_v3_v3fl(offset, temp, sdbind->influence);
1400 }
1401 /* Subtract the vertex coord to get the deformation offset. */
1402 sub_v3_v3(offset, vertexCos);
1403
1404 /* Add the offset to start coord multiplied by the strength and weight values. */
1405 madd_v3_v3fl(vertexCos, offset, data->strength * weight);
1406}
1407
1409 const ModifierEvalContext *ctx,
1410 float (*vertexCos)[3],
1411 uint verts_num,
1412 Object *ob,
1413 Mesh *mesh)
1414{
1416 Mesh *target;
1417 uint target_verts_num, target_faces_num;
1418
1419 /* Exit function if bind flag is not set (free bind data if any). */
1420 if (!(smd->flags & MOD_SDEF_BIND)) {
1421 if (smd->verts != nullptr) {
1422 if (!DEG_is_active(ctx->depsgraph)) {
1423 BKE_modifier_set_error(ob, md, "Attempt to bind from inactive dependency graph");
1424 return;
1425 }
1426 ModifierData *md_orig = BKE_modifier_get_original(ob, md);
1427 free_data(md_orig);
1428 }
1429 return;
1430 }
1431
1432 Object *ob_target = smd->target;
1434 if (!target) {
1435 BKE_modifier_set_error(ob, md, "No valid target mesh");
1436 return;
1437 }
1438
1439 target_verts_num = BKE_mesh_wrapper_vert_len(target);
1440 target_faces_num = BKE_mesh_wrapper_face_len(target);
1441
1442 /* If not bound, execute bind. */
1443 if (smd->verts == nullptr) {
1444 if (!DEG_is_active(ctx->depsgraph)) {
1445 BKE_modifier_set_error(ob, md, "Attempt to unbind from inactive dependency graph");
1446 return;
1447 }
1448
1450 ob, md);
1451 float tmp_mat[4][4];
1452
1453 invert_m4_m4(tmp_mat, ob->object_to_world().ptr());
1454 mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->object_to_world().ptr());
1455
1456 /* Avoid converting edit-mesh data, binding is an exception. */
1458
1459 if (!surfacedeformBind(ob,
1460 smd_orig,
1461 smd,
1462 vertexCos,
1463 verts_num,
1464 target_faces_num,
1465 target_verts_num,
1466 target,
1467 mesh))
1468 {
1469 smd->flags &= ~MOD_SDEF_BIND;
1470 }
1471 /* Early abort, this is binding 'call', no need to perform whole evaluation. */
1472 return;
1473 }
1474
1475 /* Geometry count on the deforming mesh. */
1476 if (smd->mesh_verts_num != verts_num) {
1478 ob, md, "Vertices changed from %u to %u", smd->mesh_verts_num, verts_num);
1479 return;
1480 }
1481
1482 /* Geometry count on the target mesh. */
1483 if (smd->target_polys_num != target_faces_num && smd->target_verts_num == 0) {
1484 /* Change in the number of polygons does not really imply change in the vertex count, but
1485 * this is how the modifier worked before the vertex count was known. Follow the legacy
1486 * logic without requirement to re-bind the mesh. */
1488 ob, md, "Target polygons changed from %u to %u", smd->target_polys_num, target_faces_num);
1489 return;
1490 }
1491 if (!ELEM(smd->target_verts_num, 0, target_verts_num)) {
1492 if (smd->target_verts_num > target_verts_num) {
1493 /* Number of vertices on the target did reduce. There is no usable recovery from this. */
1495 md,
1496 "Target vertices changed from %u to %u",
1497 smd->target_verts_num,
1498 target_verts_num);
1499 return;
1500 }
1501
1502 /* Assume the increase in the vertex count means that the "new" vertices in the target mesh are
1503 * added after the original ones. This covers typical case when target was at the subdivision
1504 * level 0 and then subdivision was increased (i.e. for the render purposes). */
1505
1507 md,
1508 "Target vertices changed from %u to %u, continuing anyway",
1509 smd->target_verts_num,
1510 target_verts_num);
1511
1512 /* In theory we only need the `smd->verts_num` vertices in the `targetCos` for evaluation, but
1513 * it is not currently possible to request a subset of coordinates: the API expects that the
1514 * caller needs coordinates of all vertices and asserts for it. */
1515 }
1516
1517 /* Early out if modifier would not affect input at all - still *after* the sanity checks
1518 * (and potential binding) above. */
1519 if (smd->strength == 0.0f) {
1520 return;
1521 }
1522
1523 int defgrp_index;
1524 const MDeformVert *dvert;
1525 MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
1526 const bool invert_vgroup = (smd->flags & MOD_SDEF_INVERT_VGROUP) != 0;
1527
1528 /* Actual vertex location update starts here */
1530 data.bind_verts = smd->verts;
1531 data.targetCos = MEM_malloc_arrayN<float[3]>(size_t(target_verts_num), "SDefTargetVertArray");
1532 data.vertexCos = vertexCos;
1533 data.dvert = dvert;
1534 data.defgrp_index = defgrp_index;
1535 data.invert_vgroup = invert_vgroup;
1536 data.strength = smd->strength;
1537
1538 if (data.targetCos != nullptr) {
1540 target, data.targetCos, target_verts_num, smd->mat);
1541
1542 TaskParallelSettings settings;
1544 settings.use_threading = (smd->bind_verts_num > 10000);
1546
1547 MEM_freeN(data.targetCos);
1548 }
1549}
1550
1552 const ModifierEvalContext *ctx,
1553 Mesh *mesh,
1555{
1557 ctx,
1558 reinterpret_cast<float(*)[3]>(positions.data()),
1559 positions.size(),
1560 ctx->object,
1561 mesh);
1562}
1563
1564static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
1565{
1567
1568 /* The object type check is only needed here in case we have a placeholder
1569 * object assigned (because the library containing the mesh is missing).
1570 *
1571 * In other cases it should be impossible to have a type mismatch.
1572 */
1573 return (smd->target == nullptr || smd->target->type != OB_MESH) &&
1574 !(smd->verts != nullptr && !(smd->flags & MOD_SDEF_BIND));
1575}
1576
1577static void panel_draw(const bContext * /*C*/, Panel *panel)
1578{
1579 uiLayout *col;
1580 uiLayout *layout = panel->layout;
1581
1582 PointerRNA ob_ptr;
1584
1585 PointerRNA target_ptr = RNA_pointer_get(ptr, "target");
1586
1587 bool is_bound = RNA_boolean_get(ptr, "is_bound");
1588
1589 uiLayoutSetPropSep(layout, true);
1590
1591 col = &layout->column(false);
1592 uiLayoutSetActive(col, !is_bound);
1593 col->prop(ptr, "target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1594 col->prop(ptr, "falloff", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1595
1596 layout->prop(ptr, "strength", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1597
1598 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
1599
1600 col = &layout->column(false);
1601 uiLayoutSetEnabled(col, !is_bound);
1602 uiLayoutSetActive(col, !is_bound && RNA_string_length(ptr, "vertex_group") != 0);
1603 col->prop(ptr, "use_sparse_bind", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1604
1605 layout->separator();
1606
1607 col = &layout->column(false);
1608 if (is_bound) {
1609 col->op("OBJECT_OT_surfacedeform_bind", IFACE_("Unbind"), ICON_NONE);
1610 }
1611 else {
1613 col->op("OBJECT_OT_surfacedeform_bind", IFACE_("Bind"), ICON_NONE);
1614 }
1616}
1617
1618static void panel_register(ARegionType *region_type)
1619{
1621}
1622
1623static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
1624{
1626 const bool is_undo = BLO_write_is_undo(writer);
1627
1628 if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
1629 BLI_assert(!ID_IS_LINKED(id_owner));
1630 const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
1631 if (!is_local) {
1632 /* Modifier coming from linked data cannot be bound from an override, so we can remove all
1633 * binding data, can save a significant amount of memory. */
1634 smd.bind_verts_num = 0;
1635 smd.verts = nullptr;
1636 }
1637 }
1638
1640
1641 if (smd.verts != nullptr) {
1642 SDefVert *bind_verts = smd.verts;
1643 BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
1644
1645 for (int i = 0; i < smd.bind_verts_num; i++) {
1646 BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
1647
1648 if (bind_verts[i].binds) {
1649 for (int j = 0; j < bind_verts[i].binds_num; j++) {
1651 writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
1652
1653 if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
1654 {
1655 BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
1656 }
1657 else {
1659 writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_weights);
1660 }
1661 }
1662 }
1663 }
1664 }
1665}
1666
1667static void blend_read(BlendDataReader *reader, ModifierData *md)
1668{
1670
1671 BLO_read_struct_array(reader, SDefVert, smd->bind_verts_num, &smd->verts);
1672
1673 if (smd->verts) {
1674 for (int i = 0; i < smd->bind_verts_num; i++) {
1675 BLO_read_struct_array(reader, SDefBind, smd->verts[i].binds_num, &smd->verts[i].binds);
1676
1677 if (smd->verts[i].binds) {
1678 for (int j = 0; j < smd->verts[i].binds_num; j++) {
1680 reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
1681
1683 {
1684 BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
1685 }
1686 else {
1688 reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_weights);
1689 }
1690 }
1691 }
1692 }
1693 }
1694}
1695
1697 /*idname*/ "SurfaceDeform",
1698 /*name*/ N_("SurfaceDeform"),
1699 /*struct_name*/ "SurfaceDeformModifierData",
1700 /*struct_size*/ sizeof(SurfaceDeformModifierData),
1701 /*srna*/ &RNA_SurfaceDeformModifier,
1704 /*icon*/ ICON_MOD_MESHDEFORM,
1705
1706 /*copy_data*/ copy_data,
1707
1708 /*deform_verts*/ deform_verts,
1709 /*deform_matrices*/ nullptr,
1710 /*deform_verts_EM*/ nullptr,
1711 /*deform_matrices_EM*/ nullptr,
1712 /*modify_mesh*/ nullptr,
1713 /*modify_geometry_set*/ nullptr,
1714
1715 /*init_data*/ init_data,
1716 /*required_data_mask*/ required_data_mask,
1717 /*free_data*/ free_data,
1718 /*is_disabled*/ is_disabled,
1719 /*update_depsgraph*/ update_depsgraph,
1720 /*depends_on_time*/ nullptr,
1721 /*depends_on_normals*/ nullptr,
1722 /*foreach_ID_link*/ foreach_ID_link,
1723 /*foreach_tex_link*/ nullptr,
1724 /*free_runtime_data*/ nullptr,
1725 /*panel_register*/ panel_register,
1726 /*blend_write*/ blend_write,
1727 /*blend_read*/ blend_read,
1728 /*foreach_cache*/ nullptr,
1729};
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:763
@ 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)
void BLO_write_float_array(BlendWriter *writer, int64_t num, const float *data_ptr)
void BLO_read_float3_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5336
void BLO_read_uint32_array(BlendDataReader *reader, int64_t array_size, uint32_t **ptr_p)
Definition readfile.cc:5316
void BLO_read_float_array(BlendDataReader *reader, int64_t array_size, float **ptr_p)
Definition readfile.cc:5326
void BLO_write_float3_array(BlendWriter *writer, int64_t num, const float *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
void BLO_write_uint32_array(BlendWriter *writer, int64_t num, const uint32_t *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:323
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
#define DNA_struct_default_get(struct_name)
@ eModifierFlag_OverrideLibrary_Local
@ MOD_SDEF_MODE_CENTROID
@ MOD_SDEF_MODE_NGONS
@ MOD_SDEF_MODE_CORNER_TRIS
@ MOD_SDEF_BIND
@ MOD_SDEF_INVERT_VGROUP
@ MOD_SDEF_SPARSE_BIND
@ eModifierType_SurfaceDeform
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.
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:271
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)
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_INFINITE_WEIGHT_DIST
@ MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ
@ MOD_SDEF_INFINITE_WEIGHT_ANGULAR
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)
@ 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
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
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#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
const T * data() const
Definition BLI_array.hh:301
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
#define sinf(x)
#define powf(x, y)
#define fabsf(x)
#define sqrtf(x)
static ushort indices[]
uint col
#define isnan
#define CD_MASK_MDEFORMVERT
#define MEM_SAFE_FREE(v)
#define ID_IS_LINKED(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
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_reallocN_id)(void *vmemh, size_t len, const char *str)
Definition mallocn.cc:40
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_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float sqr(const float a)
Definition math_base.h:600
VecBase< int32_t, 2 > int2
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:404
int edges_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
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
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:4226
uint8_t flag
Definition wm_window.cc:139