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