Blender V4.5
shrinkwrap.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cfloat>
11#include <cmath>
12#include <cstdio>
13#include <cstring>
14#include <ctime>
15#include <memory.h>
16
18#include "DNA_mesh_types.h"
19#include "DNA_modifier_types.h"
20#include "DNA_object_types.h"
21
22#include "BLI_math_geom.h"
23#include "BLI_math_matrix.h"
24#include "BLI_math_solvers.h"
25#include "BLI_math_vector.h"
26#include "BLI_task.h"
27#include "BLI_utildefines.h"
28
29#include "BKE_attribute.hh"
31#include "BKE_modifier.hh"
32#include "BKE_shrinkwrap.hh"
33
34#include "BKE_deform.hh"
35#include "BKE_editmesh.hh"
36#include "BKE_mesh.hh" /* for OMP limits. */
37#include "BKE_mesh_wrapper.hh"
38#include "BKE_subsurf.hh"
39
41
42#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
43
44/* for timing... */
45#if 0
46# include "BLI_time_utildefines.h"
47#else
48# define TIMEIT_BENCH(expr, id) (expr)
49#endif
50
51/* Util macros */
52#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
53
55 ShrinkwrapModifierData *smd; /* shrinkwrap modifier data */
56
57 Object *ob; /* object we are applying shrinkwrap to */
58
59 float (*vert_positions)[3]; /* Array of verts being projected. */
61 /* Vertices being shrink-wrapped. */
62 float (*vertexCos)[3];
64
65 const MDeformVert *dvert; /* Pointer to mdeform array */
66 int vgroup; /* Vertex group num */
67 bool invert_vgroup; /* invert vertex group influence */
68
69 Mesh *target; /* mesh we are shrinking to */
70 SpaceTransform local2target; /* transform to move between local and target space */
71 ShrinkwrapTreeData *tree; /* mesh BVH tree data */
72
74
75 float keepDist; /* Distance to keep above target surface (units are in local space) */
76};
77
87
88bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
89{
90 return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
91 (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX &&
92 shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
93}
94
96 ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
97{
98 using namespace blender::bke;
99 *data = {};
100
101 if (mesh == nullptr) {
102 return false;
103 }
104
105 /* We could create a BVH tree from the edit mesh,
106 * however accessing normals from the face/loop normals gets more involved.
107 * Convert mesh data since this isn't typically used in edit-mode. */
109
110 if (mesh->verts_num <= 0) {
111 return false;
112 }
113
114 data->mesh = mesh;
115 data->edges = mesh->edges();
116 data->faces = mesh->faces();
117 data->corner_edges = mesh->corner_edges();
118 data->vert_normals = mesh->vert_normals();
119 const AttributeAccessor attributes = mesh->attributes();
120 data->sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
121
122 if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
123 data->treeData = mesh->bvh_verts();
124 data->bvh = data->treeData.tree;
125 return data->bvh != nullptr;
126 }
127
128 if (mesh->faces_num <= 0) {
129 return false;
130 }
131
132 data->treeData = mesh->bvh_corner_tris();
133 data->bvh = data->treeData.tree;
134
135 if (data->bvh == nullptr) {
136 return false;
137 }
138
139 if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
140 data->face_normals = mesh->face_normals();
141 if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
142 data->corner_normals = mesh->corner_normals();
143 }
144 }
145
146 if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
148 }
149
150 return true;
151}
152
154
155namespace blender::bke::shrinkwrap {
156
157/* Accumulate edge for average boundary edge direction. */
159 MutableSpan<int8_t> status,
160 int index,
161 const float edge_dir[3],
162 signed char side)
163{
164 BLI_assert(index >= 0);
165 float *direction = vdata[index].direction;
166
167 /* Invert the direction vector if either:
168 * - This is the second edge and both edges have the vertex as start or end.
169 * - For third and above, if it points in the wrong direction.
170 */
171 if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) {
172 sub_v3_v3(direction, edge_dir);
173 }
174 else {
175 add_v3_v3(direction, edge_dir);
176 }
177
178 status[index] = (status[index] == 0) ? side : -1;
179}
180
182{
183 const Span<float3> positions = mesh.vert_positions();
184 const Span<int2> edges = mesh.edges();
185 const Span<int> corner_verts = mesh.corner_verts();
186 const Span<int> corner_edges = mesh.corner_edges();
187
188 /* Count faces per edge (up to 2). */
189 Array<int8_t> edge_mode(edges.size(), 0);
190
191 for (const int edge : corner_edges) {
192 if (edge_mode[edge] < 2) {
193 edge_mode[edge]++;
194 }
195 }
196
197 /* Build the boundary edge bitmask. */
198 BitVector<> edge_is_boundary(mesh.edges_num, false);
199
200 int num_boundary_edges = 0;
201 for (const int64_t i : edges.index_range()) {
202 if (edge_mode[i] == 1) {
203 edge_is_boundary[i].set();
204 num_boundary_edges++;
205 }
206 }
207
208 /* If no boundary, return nullptr. */
209 if (num_boundary_edges == 0) {
210 return {};
211 }
212
213 /* Allocate the data object. */
215
216 /* Build the boundary corner_tris bit-mask. */
217 const Span<int3> corner_tris = mesh.corner_tris();
218
219 BitVector<> tri_has_boundary(corner_tris.size(), false);
220
221 for (const int64_t i : corner_tris.index_range()) {
223 edges, corner_verts, corner_edges, corner_tris[i]);
224
225 for (int j = 0; j < 3; j++) {
226 if (real_edges[j] >= 0 && edge_is_boundary[real_edges[j]]) {
227 tri_has_boundary[i].set();
228 break;
229 }
230 }
231 }
232
233 /* Find boundary vertices and build a mapping table for compact storage of data. */
234 Array<int> vert_boundary_id(mesh.verts_num, 0);
235
236 for (const int64_t i : edges.index_range()) {
237 if (edge_is_boundary[i]) {
238 const int2 &edge = edges[i];
239 vert_boundary_id[edge[0]] = 1;
240 vert_boundary_id[edge[1]] = 1;
241 }
242 }
243
244 int boundary_verts_num = 0;
245 for (const int64_t i : positions.index_range()) {
246 vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? boundary_verts_num++ : -1;
247 }
248
249 /* Compute average directions. */
250 Array<ShrinkwrapBoundaryVertData> boundary_verts(boundary_verts_num);
251
252 Array<int8_t> vert_status(boundary_verts_num);
253 for (const int64_t i : edges.index_range()) {
254 if (edge_is_boundary[i]) {
255 const int2 &edge = edges[i];
256
257 float dir[3];
258 sub_v3_v3v3(dir, positions[edge[1]], positions[edge[0]]);
259 normalize_v3(dir);
260
261 merge_vert_dir(boundary_verts.data(), vert_status, vert_boundary_id[edge[0]], dir, 1);
262 merge_vert_dir(boundary_verts.data(), vert_status, vert_boundary_id[edge[1]], dir, 2);
263 }
264 }
265
266 /* Finalize average direction and compute normal. */
267 const Span<float3> vert_normals = mesh.vert_normals();
268 for (const int64_t i : positions.index_range()) {
269 int bidx = vert_boundary_id[i];
270
271 if (bidx >= 0) {
272 ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
273 float tmp[3];
274
275 normalize_v3(vdata->direction);
276
277 cross_v3_v3v3(tmp, vert_normals[i], vdata->direction);
278 cross_v3_v3v3(vdata->normal_plane, tmp, vert_normals[i]);
280 }
281 }
282
283 data.edge_is_boundary = std::move(edge_is_boundary);
284 data.tri_has_boundary = std::move(tri_has_boundary);
285 data.vert_boundary_id = std::move(vert_boundary_id);
286 data.boundary_verts = std::move(boundary_verts);
287
288 return data;
289}
290
292{
293 mesh.runtime->shrinkwrap_boundary_cache.ensure(
295 return mesh.runtime->shrinkwrap_boundary_cache.data();
296}
297
298} // namespace blender::bke::shrinkwrap
299
306static void shrinkwrap_calc_nearest_vertex_cb_ex(void *__restrict userdata,
307 const int i,
308 const TaskParallelTLS *__restrict tls)
309{
310 ShrinkwrapCalcCBData *data = static_cast<ShrinkwrapCalcCBData *>(userdata);
311
312 ShrinkwrapCalcData *calc = data->calc;
313 blender::bke::BVHTreeFromMesh *treeData = &data->tree->treeData;
314 BVHTreeNearest *nearest = static_cast<BVHTreeNearest *>(tls->userdata_chunk);
315
316 float *co = calc->vertexCos[i];
317 float tmp_co[3];
319 calc->dvert, i, calc->vgroup, calc->invert_vgroup);
320
321 if (weight == 0.0f) {
322 return;
323 }
324
325 /* Convert the vertex to tree coordinates */
326 if (calc->vert_positions) {
327 copy_v3_v3(tmp_co, calc->vert_positions[i]);
328 }
329 else {
330 copy_v3_v3(tmp_co, co);
331 }
333
334 /* Use local proximity heuristics (to reduce the nearest search)
335 *
336 * If we already had an hit before.. we assume this vertex is going to have a close hit to that
337 * other vertex so we can initiate the "nearest.dist" with the expected value to that last hit.
338 * This will lead in pruning of the search tree. */
339 if (nearest->index != -1) {
340 nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
341 }
342 else {
343 nearest->dist_sq = FLT_MAX;
344 }
345
346 BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
347
348 /* Found the nearest vertex */
349 if (nearest->index != -1) {
350 /* Adjusting the vertex weight,
351 * so that after interpolating it keeps a certain distance from the nearest position */
352 if (nearest->dist_sq > FLT_EPSILON) {
353 const float dist = sqrtf(nearest->dist_sq);
354 weight *= (dist - calc->keepDist) / dist;
355 }
356
357 /* Convert the coordinates back to mesh coordinates */
358 copy_v3_v3(tmp_co, nearest->co);
360
361 interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
362 }
363}
364
366{
368
369 /* Setup nearest */
370 nearest.index = -1;
371 nearest.dist_sq = FLT_MAX;
372
374 data.calc = calc;
375 data.tree = calc->tree;
376 TaskParallelSettings settings;
378 settings.use_threading = (calc->numVerts > 10000);
379 settings.userdata_chunk = &nearest;
380 settings.userdata_chunk_size = sizeof(nearest);
382 0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings);
383}
384
386 const float vert[3],
387 const float dir[3],
388 const float ray_radius,
389 const SpaceTransform *transf,
391 BVHTreeRayHit *hit)
392{
393 /* don't use this because this dist value could be incompatible
394 * this value used by the callback for comparing previous/new dist values.
395 * also, at the moment there is no need to have a corrected 'dist' value */
396 // #define USE_DIST_CORRECT
397
398 float tmp_co[3], tmp_no[3];
399 const float *co, *no;
400 BVHTreeRayHit hit_tmp;
401
402 /* Copy from hit (we need to convert hit rays from one space coordinates to the other */
403 memcpy(&hit_tmp, hit, sizeof(hit_tmp));
404
405 /* Apply space transform (TODO readjust dist) */
406 if (transf) {
407 copy_v3_v3(tmp_co, vert);
408 BLI_space_transform_apply(transf, tmp_co);
409 co = tmp_co;
410
411 copy_v3_v3(tmp_no, dir);
412 BLI_space_transform_apply_normal(transf, tmp_no);
413 no = tmp_no;
414
415#ifdef USE_DIST_CORRECT
416 hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target);
417#endif
418 }
419 else {
420 co = vert;
421 no = dir;
422 }
423
424 hit_tmp.index = -1;
425
427 tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData);
428
429 if (hit_tmp.index != -1) {
430 /* invert the normal first so face culling works on rotated objects */
431 if (transf) {
432 BLI_space_transform_invert_normal(transf, hit_tmp.no);
433 }
434
436 /* Apply back-face. */
437 const float dot = dot_v3v3(dir, hit_tmp.no);
438 if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
440 {
441 return false; /* Ignore hit */
442 }
443 }
444
445 if (transf) {
446 /* Inverting space transform (TODO: make coherent with the initial dist readjust). */
447 BLI_space_transform_invert(transf, hit_tmp.co);
448#ifdef USE_DIST_CORRECT
449 hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
450#endif
451 }
452
453 BLI_assert(hit_tmp.dist <= hit->dist);
454
455 memcpy(hit, &hit_tmp, sizeof(hit_tmp));
456 return true;
457 }
458 return false;
459}
460
461static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata,
462 const int i,
463 const TaskParallelTLS *__restrict tls)
464{
465 ShrinkwrapCalcCBData *data = static_cast<ShrinkwrapCalcCBData *>(userdata);
466
467 ShrinkwrapCalcData *calc = data->calc;
469 ShrinkwrapTreeData *aux_tree = data->aux_tree;
470
471 float *proj_axis = data->proj_axis;
472 SpaceTransform *local2aux = data->local2aux;
473
474 BVHTreeRayHit *hit = static_cast<BVHTreeRayHit *>(tls->userdata_chunk);
475
476 const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
477 float *co = calc->vertexCos[i];
478 const float *tmp_co, *tmp_no;
480 calc->dvert, i, calc->vgroup, calc->invert_vgroup);
481
482 if (weight == 0.0f) {
483 return;
484 }
485
486 if (calc->vert_positions != nullptr && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)
487 {
488 /* calc->vert_positions contains verts from evaluated mesh. */
489 /* These coordinates are deformed by vertexCos only for normal projection
490 * (to get correct normals) for other cases calc->verts contains undeformed coordinates and
491 * vertexCos should be used */
492 tmp_co = calc->vert_positions[i];
493 tmp_no = calc->vert_normals[i];
494 }
495 else {
496 tmp_co = co;
497 tmp_no = proj_axis;
498 }
499
500 hit->index = -1;
501
502 /* TODO: we should use FLT_MAX here, but sweep-sphere code isn't prepared for that. */
504
505 bool is_aux = false;
506
507 /* Project over positive direction of axis. */
509 if (aux_tree) {
510 if (BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, 0.0, local2aux, aux_tree, hit)) {
511 is_aux = true;
512 }
513 }
514
516 calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, &calc->local2target, tree, hit))
517 {
518 is_aux = false;
519 }
520 }
521
522 /* Project over negative direction of axis */
524 float inv_no[3];
525 negate_v3_v3(inv_no, tmp_no);
526
527 char options = calc->smd->shrinkOpts;
528
531 {
533 }
534
535 if (aux_tree) {
536 if (BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, 0.0, local2aux, aux_tree, hit)) {
537 is_aux = true;
538 }
539 }
540
542 options, tmp_co, inv_no, 0.0, &calc->local2target, tree, hit))
543 {
544 is_aux = false;
545 }
546 }
547
548 /* don't set the initial dist (which is more efficient),
549 * because its calculated in the targets space, we want the dist in our own space */
550 if (proj_limit_squared != 0.0f) {
551 if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
552 hit->index = -1;
553 }
554 }
555
556 if (hit->index != -1) {
557 if (is_aux) {
559 local2aux,
560 calc->smd->shrinkMode,
561 hit->index,
562 hit->co,
563 hit->no,
564 calc->keepDist,
565 tmp_co,
566 hit->co);
567 }
568 else {
570 &calc->local2target,
571 calc->smd->shrinkMode,
572 hit->index,
573 hit->co,
574 hit->no,
575 calc->keepDist,
576 tmp_co,
577 hit->co);
578 }
579
580 interp_v3_v3v3(co, co, hit->co, weight);
581 }
582}
583
585{
586 /* Options about projection direction */
587 float proj_axis[3] = {0.0f, 0.0f, 0.0f};
588
589 /* Ray-cast and tree stuff. */
590
594 BVHTreeRayHit hit;
595
596 /* auxiliary target */
597 Mesh *auxMesh = nullptr;
598 ShrinkwrapTreeData *aux_tree = nullptr;
599 ShrinkwrapTreeData aux_tree_stack;
600 SpaceTransform local2aux;
601
602 /* If the user doesn't allows to project in any direction of projection axis
603 * then there's nothing todo. */
604 if ((calc->smd->shrinkOpts &
606 {
607 return;
608 }
609
610 /* Prepare data to retrieve the direction in which we should project each vertex */
612 if (calc->vert_positions == nullptr) {
613 return;
614 }
615 }
616 else {
617 /* The code supports any axis that is a combination of X,Y,Z
618 * although currently UI only allows to set the 3 different axis */
620 proj_axis[0] = 1.0f;
621 }
623 proj_axis[1] = 1.0f;
624 }
626 proj_axis[2] = 1.0f;
627 }
628
629 normalize_v3(proj_axis);
630
631 /* Invalid projection direction */
632 if (len_squared_v3(proj_axis) < FLT_EPSILON) {
633 return;
634 }
635 }
636
637 if (calc->aux_target) {
639 if (!auxMesh) {
640 return;
641 }
642 BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->aux_target);
643 }
644
646 &aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false))
647 {
648 aux_tree = &aux_tree_stack;
649 }
650
651 /* After successfully build the trees, start projection vertices. */
653 data.calc = calc;
654 data.tree = calc->tree;
655 data.aux_tree = aux_tree;
656 data.proj_axis = proj_axis;
657 data.local2aux = &local2aux;
658 TaskParallelSettings settings;
660 settings.use_threading = (calc->numVerts > 10000);
661 settings.userdata_chunk = &hit;
662 settings.userdata_chunk_size = sizeof(hit);
665
666 /* free data structures */
667 if (aux_tree) {
668 BKE_shrinkwrap_free_tree(aux_tree);
669 }
670}
671
672/*
673 * Shrinkwrap Target Surface Project mode
674 *
675 * It uses Newton's method to find a surface location with its
676 * smooth normal pointing at the original point.
677 *
678 * The equation system on barycentric weights and normal multiplier:
679 *
680 * (w0*V0 + w1*V1 + w2*V2) + l * (w0*N0 + w1*N1 + w2*N2) - CO = 0
681 * w0 + w1 + w2 = 1
682 *
683 * The actual solution vector is [ w0, w1, l ], with w2 eliminated.
684 */
685
686// #define TRACE_TARGET_PROJECT
687
689 const float **vtri_co;
690 const float (*vtri_no)[3];
691 const float *point_co;
692
695
696 /* Current interpolated position and normal. */
697 float co_interp[3], no_interp[3];
698};
699
700/* Computes the deviation of the equation system from goal. */
701static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3])
702{
703 TargetProjectTriData *data = static_cast<TargetProjectTriData *>(userdata);
704
705 const float w[3] = {x[0], x[1], 1.0f - x[0] - x[1]};
706 interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w);
707 interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w);
708
709 madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]);
710 sub_v3_v3(r_delta, data->point_co);
711}
712
713/* Computes the Jacobian matrix of the equation system. */
714static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3])
715{
716 TargetProjectTriData *data = static_cast<TargetProjectTriData *>(userdata);
717
718 madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]);
719 madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]);
720
721 copy_v3_v3(r_jacobian[2], data->vtri_no[2]);
722 madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]);
723 madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]);
724}
725
726/* Clamp barycentric weights to the triangle. */
727static void target_project_tri_clamp(float x[3])
728{
729 x[0] = std::max(x[0], 0.0f);
730 x[1] = std::max(x[1], 0.0f);
731 if (x[0] + x[1] > 1.0f) {
732 x[0] = x[0] / (x[0] + x[1]);
733 x[1] = 1.0f - x[0];
734 }
735}
736
737/* Correct the Newton's method step to keep the coordinates within the triangle. */
738static bool target_project_tri_correct(void * /*userdata*/,
739 const float x[3],
740 float step[3],
741 float x_next[3])
742{
743 /* Insignificant correction threshold */
744 const float epsilon = 1e-5f;
745 /* Dot product threshold for checking if step is 'clearly' pointing outside. */
746 const float dir_epsilon = 0.5f;
747 bool fixed = false, locked = false;
748
749 /* The barycentric coordinate domain is a triangle bounded by
750 * the X and Y axes, plus the x+y=1 diagonal. First, clamp the
751 * movement against the diagonal. Note that step is subtracted. */
752 float sum = x[0] + x[1];
753 float sstep = -(step[0] + step[1]);
754
755 if (sum + sstep > 1.0f) {
756 float ldist = 1.0f - sum;
757
758 /* If already at the boundary, slide along it. */
759 if (ldist < epsilon * float(M_SQRT2)) {
760 float step_len = len_v2(step);
761
762 /* Abort if the solution is clearly outside the domain. */
763 if (step_len > epsilon && sstep > step_len * dir_epsilon * float(M_SQRT2)) {
764 return false;
765 }
766
767 /* Project the new position onto the diagonal. */
768 add_v2_fl(step, (sum + sstep - 1.0f) * 0.5f);
769 fixed = locked = true;
770 }
771 else {
772 /* Scale a significant step down to arrive at the boundary. */
773 mul_v3_fl(step, ldist / sstep);
774 fixed = true;
775 }
776 }
777
778 /* Weight 0 and 1 boundary checks - along axis. */
779 for (int i = 0; i < 2; i++) {
780 if (step[i] > x[i]) {
781 /* If already at the boundary, slide along it. */
782 if (x[i] < epsilon) {
783 float step_len = len_v2(step);
784
785 /* Abort if the solution is clearly outside the domain. */
786 if (step_len > epsilon && (locked || step[i] > step_len * dir_epsilon)) {
787 return false;
788 }
789
790 /* Reset precision errors to stay at the boundary. */
791 step[i] = x[i];
792 fixed = true;
793 }
794 else {
795 /* Scale a significant step down to arrive at the boundary. */
796 mul_v3_fl(step, x[i] / step[i]);
797 fixed = true;
798 }
799 }
800 }
801
802 /* Recompute and clamp the new coordinates after step correction. */
803 if (fixed) {
804 sub_v3_v3v3(x_next, x, step);
806 }
807
808 return true;
809}
810
811static bool target_project_solve_point_tri(const float *vtri_co[3],
812 const float vtri_no[3][3],
813 const float point_co[3],
814 const float hit_co[3],
815 float hit_dist_sq,
816 float r_hit_co[3],
817 float r_hit_no[3])
818{
819 float x[3], tmp[3];
820 float dist = sqrtf(hit_dist_sq);
821 float magnitude_estimate = dist + len_manhattan_v3(vtri_co[0]) + len_manhattan_v3(vtri_co[1]) +
822 len_manhattan_v3(vtri_co[2]);
823 float epsilon = magnitude_estimate * 1.0e-6f;
824
825 /* Initial solution vector: barycentric weights plus distance along normal. */
826 interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
827
828 interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x);
829 sub_v3_v3v3(tmp, point_co, hit_co);
830
831 x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist;
832
833 /* Solve the equations iteratively. */
834 TargetProjectTriData tri_data{};
835 tri_data.vtri_co = vtri_co;
836 tri_data.vtri_no = vtri_no;
837 tri_data.point_co = point_co;
838
839 sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]);
840 sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]);
841 sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]);
842 sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]);
843
845
846#ifdef TRACE_TARGET_PROJECT
847 const bool trace = true;
848#else
849 const bool trace = false;
850#endif
851
855 &tri_data,
856 epsilon,
857 20,
858 trace,
859 x,
860 x);
861
862 if (ok) {
863 copy_v3_v3(r_hit_co, tri_data.co_interp);
864 copy_v3_v3(r_hit_no, tri_data.no_interp);
865
866 return true;
867 }
868
869 return false;
870}
871
872static bool update_hit(BVHTreeNearest *nearest,
873 int index,
874 const float co[3],
875 const float hit_co[3],
876 const float hit_no[3])
877{
878 float dist_sq = len_squared_v3v3(hit_co, co);
879
880 if (dist_sq < nearest->dist_sq) {
881#ifdef TRACE_TARGET_PROJECT
882 printf(
883 "#=#=#> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
884#endif
885 nearest->index = index;
886 nearest->dist_sq = dist_sq;
887 copy_v3_v3(nearest->co, hit_co);
888 normalize_v3_v3(nearest->no, hit_no);
889 return true;
890 }
891
892 return false;
893}
894
895/* Target projection on a non-manifold boundary edge -
896 * treats it like an infinitely thin cylinder. */
898 int index,
899 const float co[3],
900 BVHTreeNearest *nearest,
901 int eidx)
902{
903 const blender::bke::BVHTreeFromMesh *data = &tree->treeData;
904 const blender::int2 &edge = tree->edges[eidx];
905 const float *vedge_co[2] = {data->vert_positions[edge[0]], data->vert_positions[edge[1]]};
906
907#ifdef TRACE_TARGET_PROJECT
908 printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n",
909 eidx,
910 UNPACK3(vedge_co[0]),
911 UNPACK3(vedge_co[1]));
912#endif
913
914 /* Retrieve boundary vertex IDs */
915 const int *vert_boundary_id = tree->boundary->vert_boundary_id.data();
916 int bid1 = vert_boundary_id[edge[0]], bid2 = vert_boundary_id[edge[1]];
917
918 if (bid1 < 0 || bid2 < 0) {
919 return;
920 }
921
922 /* Retrieve boundary vertex normals and align them to direction. */
923 const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts.data();
924 float vedge_dir[2][3], dir[3];
925
926 copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane);
927 copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane);
928
929 sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]);
930
931 if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) {
932 negate_v3(vedge_dir[0]);
933 }
934 if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) {
935 negate_v3(vedge_dir[1]);
936 }
937
938 /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */
939 float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]);
940 float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]);
941 float d0co = dot_v3v3(vedge_dir[0], co);
942
943 float a = d0v1 - d0v0 + d1v0 - d1v1;
944 float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co);
945 float c = d0co - d0v0;
946 float det = b * b - 4 * a * c;
947
948 if (det >= 0 && a != 0) {
949 const float epsilon = 1e-6f;
950 float sdet = sqrtf(det);
951 float hit_co[3], hit_no[3];
952
953 for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) {
954 float x = (-b + (float(i) - 1) * sdet) / (2 * a);
955
956 if (x >= -epsilon && x <= 1.0f + epsilon) {
957 CLAMP(x, 0, 1);
958
959 float vedge_no[2][3];
960 copy_v3_v3(vedge_no[0], tree->vert_normals[edge[0]]);
961 copy_v3_v3(vedge_no[1], tree->vert_normals[edge[1]]);
962
963 interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
964 interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
965
966 update_hit(nearest, index, co, hit_co, hit_no);
967 }
968 }
969 }
970}
971
972/* Target normal projection BVH callback - based on mesh_corner_tri_nearest_point. */
973static void mesh_corner_tris_target_project(void *userdata,
974 int index,
975 const float co[3],
976 BVHTreeNearest *nearest)
977{
978 using namespace blender;
979 const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
980 const blender::bke::BVHTreeFromMesh *data = &tree->treeData;
981 const int3 &tri = data->corner_tris[index];
982 const int tri_verts[3] = {
983 data->corner_verts[tri[0]],
984 data->corner_verts[tri[1]],
985 data->corner_verts[tri[2]],
986 };
987 const float *vtri_co[3] = {
988 data->vert_positions[tri_verts[0]],
989 data->vert_positions[tri_verts[1]],
990 data->vert_positions[tri_verts[2]],
991 };
992 float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3];
993
994 /* First find the closest point and bail out if it's worse than the current solution. */
995 closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co));
996 dist_sq = len_squared_v3v3(co, raw_hit_co);
997
998#ifdef TRACE_TARGET_PROJECT
999 printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n",
1000 index,
1001 UNPACK3(vtri_co[0]),
1002 UNPACK3(vtri_co[1]),
1003 UNPACK3(vtri_co[2]),
1004 dist_sq,
1005 nearest->dist_sq);
1006#endif
1007
1008 if (dist_sq >= nearest->dist_sq) {
1009 return;
1010 }
1011
1012 /* Decode normals */
1013 copy_v3_v3(vtri_no[0], tree->vert_normals[tri_verts[0]]);
1014 copy_v3_v3(vtri_no[1], tree->vert_normals[tri_verts[1]]);
1015 copy_v3_v3(vtri_no[2], tree->vert_normals[tri_verts[2]]);
1016
1017 /* Solve the equations for the triangle */
1018 if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
1019 update_hit(nearest, index, co, hit_co, hit_no);
1020 }
1021 /* Boundary edges */
1022 else if (tree->boundary && tree->boundary->has_boundary() &&
1023 tree->boundary->tri_has_boundary[index])
1024 {
1025 const BitSpan is_boundary = tree->boundary->edge_is_boundary;
1027 tree->edges, data->corner_verts, tree->corner_edges, tri);
1028
1029 for (int i = 0; i < 3; i++) {
1030 if (edges[i] >= 0 && is_boundary[edges[i]]) {
1031 target_project_edge(tree, index, co, nearest, edges[i]);
1032 }
1033 }
1034 }
1035}
1036
1038 BVHTreeNearest *nearest,
1039 float co[3],
1040 int type)
1041{
1042 blender::bke::BVHTreeFromMesh *treeData = &tree->treeData;
1043
1044 if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
1045#ifdef TRACE_TARGET_PROJECT
1046 printf("\n====== TARGET PROJECT START ======\n");
1047#endif
1048
1051
1052#ifdef TRACE_TARGET_PROJECT
1053 printf("====== TARGET PROJECT END: %d %g ======\n\n", nearest->index, nearest->dist_sq);
1054#endif
1055
1056 if (nearest->index < 0) {
1057 /* fall back to simple nearest */
1058 BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
1059 }
1060 }
1061 else {
1062 BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
1063 }
1064}
1065
1072static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdata,
1073 const int i,
1074 const TaskParallelTLS *__restrict tls)
1075{
1076 ShrinkwrapCalcCBData *data = static_cast<ShrinkwrapCalcCBData *>(userdata);
1077
1078 ShrinkwrapCalcData *calc = data->calc;
1079 BVHTreeNearest *nearest = static_cast<BVHTreeNearest *>(tls->userdata_chunk);
1080
1081 float *co = calc->vertexCos[i];
1082 float tmp_co[3];
1084 calc->dvert, i, calc->vgroup, calc->invert_vgroup);
1085
1086 if (weight == 0.0f) {
1087 return;
1088 }
1089
1090 /* Convert the vertex to tree coordinates */
1091 if (calc->vert_positions) {
1092 copy_v3_v3(tmp_co, calc->vert_positions[i]);
1093 }
1094 else {
1095 copy_v3_v3(tmp_co, co);
1096 }
1098
1099 /* Use local proximity heuristics (to reduce the nearest search)
1100 *
1101 * If we already had an hit before.. we assume this vertex is going to have a close hit to that
1102 * other vertex so we can initiate the "nearest.dist" with the expected value to that last hit.
1103 * This will lead in pruning of the search tree. */
1104 if (nearest->index != -1) {
1106 /* Heuristic doesn't work because of additional restrictions. */
1107 nearest->index = -1;
1108 nearest->dist_sq = FLT_MAX;
1109 }
1110 else {
1111 nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
1112 }
1113 }
1114 else {
1115 nearest->dist_sq = FLT_MAX;
1116 }
1117
1118 BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType);
1119
1120 /* Found the nearest vertex */
1121 if (nearest->index != -1) {
1123 nullptr,
1124 calc->smd->shrinkMode,
1125 nearest->index,
1126 nearest->co,
1127 nearest->no,
1128 calc->keepDist,
1129 tmp_co,
1130 tmp_co);
1131
1132 /* Convert the coordinates back to mesh coordinates */
1134 interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
1135 }
1136}
1137
1140 int corner_tri_idx,
1141 const float hit_co[3],
1142 const float hit_no[3],
1143 float r_no[3])
1144{
1145 using namespace blender;
1146 const blender::bke::BVHTreeFromMesh *treeData = &tree->treeData;
1147 const int3 &tri = treeData->corner_tris[corner_tri_idx];
1148 const int face_i = tree->mesh->corner_tri_faces()[corner_tri_idx];
1149
1150 /* Interpolate smooth normals if enabled. */
1151 if (tree->sharp_faces.is_empty() || tree->sharp_faces[face_i]) {
1152 const int vert_indices[3] = {treeData->corner_verts[tri[0]],
1153 treeData->corner_verts[tri[1]],
1154 treeData->corner_verts[tri[2]]};
1155 float w[3], no[3][3], tmp_co[3];
1156
1157 /* Custom and auto smooth split normals. */
1158 if (!tree->corner_normals.is_empty()) {
1159 copy_v3_v3(no[0], tree->corner_normals[tri[0]]);
1160 copy_v3_v3(no[1], tree->corner_normals[tri[1]]);
1161 copy_v3_v3(no[2], tree->corner_normals[tri[2]]);
1162 }
1163 /* Ordinary vertex normals. */
1164 else {
1165 copy_v3_v3(no[0], tree->vert_normals[vert_indices[0]]);
1166 copy_v3_v3(no[1], tree->vert_normals[vert_indices[1]]);
1167 copy_v3_v3(no[2], tree->vert_normals[vert_indices[2]]);
1168 }
1169
1170 /* Barycentric weights from hit point. */
1171 copy_v3_v3(tmp_co, hit_co);
1172
1173 if (transform) {
1175 }
1176
1178 treeData->vert_positions[vert_indices[0]],
1179 treeData->vert_positions[vert_indices[1]],
1180 treeData->vert_positions[vert_indices[2]],
1181 tmp_co);
1182
1183 /* Interpolate using weights. */
1184 interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
1185
1186 if (transform) {
1188 }
1189 else {
1190 normalize_v3(r_no);
1191 }
1192 }
1193 /* Use the face normal if flat. */
1194 else if (!tree->face_normals.is_empty()) {
1195 copy_v3_v3(r_no, tree->face_normals[face_i]);
1196 if (transform) {
1198 }
1199 }
1200 /* Finally fall back to the corner_tris normal. */
1201 else {
1202 copy_v3_v3(r_no, hit_no);
1203 }
1204}
1205
1206/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */
1207static void shrinkwrap_snap_with_side(float r_point_co[3],
1208 const float point_co[3],
1209 const float hit_co[3],
1210 const float hit_no[3],
1211 float goal_dist,
1212 float forcesign,
1213 bool forcesnap)
1214{
1215 float delta[3];
1216 sub_v3_v3v3(delta, point_co, hit_co);
1217
1218 float dist = len_v3(delta);
1219
1220 /* If exactly on the surface, push out along normal */
1221 if (dist < FLT_EPSILON) {
1222 if (forcesnap || goal_dist > 0) {
1223 madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign);
1224 }
1225 else {
1226 copy_v3_v3(r_point_co, hit_co);
1227 }
1228 }
1229 /* Move to the correct side if needed */
1230 else {
1231 float dsign = signf(dot_v3v3(delta, hit_no));
1232
1233 if (forcesign == 0.0f) {
1234 forcesign = dsign;
1235 }
1236
1237 /* If on the wrong side or too close, move to correct */
1238 if (forcesnap || dsign * dist * forcesign < goal_dist) {
1239 mul_v3_fl(delta, dsign / dist);
1240
1241 /* At very small distance, blend in the hit normal to stabilize math. */
1242 float dist_epsilon = (fabsf(goal_dist) + len_manhattan_v3(hit_co)) * 1e-4f;
1243
1244 if (dist < dist_epsilon) {
1245#ifdef TRACE_TARGET_PROJECT
1246 printf("zero_factor %g = %g / %g\n", dist / dist_epsilon, dist, dist_epsilon);
1247#endif
1248
1249 interp_v3_v3v3(delta, hit_no, delta, dist / dist_epsilon);
1250 }
1251
1252 madd_v3_v3v3fl(r_point_co, hit_co, delta, goal_dist * forcesign);
1253 }
1254 else {
1255 copy_v3_v3(r_point_co, point_co);
1256 }
1257 }
1258}
1259
1262 int mode,
1263 int hit_idx,
1264 const float hit_co[3],
1265 const float hit_no[3],
1266 float goal_dist,
1267 const float point_co[3],
1268 float r_point_co[3])
1269{
1270 float tmp[3];
1271
1272 switch (mode) {
1273 /* Offsets along the line between point_co and hit_co. */
1275 if (goal_dist != 0) {
1276 shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, 0, true);
1277 }
1278 else {
1279 copy_v3_v3(r_point_co, hit_co);
1280 }
1281 break;
1282
1284 shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false);
1285 break;
1286
1288 shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false);
1289 break;
1290
1292 if (goal_dist != 0) {
1293 shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true);
1294 }
1295 else {
1296 copy_v3_v3(r_point_co, hit_co);
1297 }
1298 break;
1299
1300 /* Offsets along the normal */
1302 if (goal_dist != 0) {
1303 BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp);
1304 madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist);
1305 }
1306 else {
1307 copy_v3_v3(r_point_co, hit_co);
1308 }
1309 break;
1310
1311 default:
1312 printf("Unknown Shrinkwrap surface snap mode: %d\n", mode);
1313 copy_v3_v3(r_point_co, hit_co);
1314 }
1315}
1316
1318{
1320
1321 /* Setup nearest */
1322 nearest.index = -1;
1323 nearest.dist_sq = FLT_MAX;
1324
1325 /* Find the nearest vertex */
1327 data.calc = calc;
1328 data.tree = calc->tree;
1329 TaskParallelSettings settings;
1331 settings.use_threading = (calc->numVerts > 10000);
1332 settings.userdata_chunk = &nearest;
1333 settings.userdata_chunk_size = sizeof(nearest);
1336}
1337
1339 const ModifierEvalContext *ctx,
1340 Scene *scene,
1341 Object *ob,
1342 Mesh *mesh,
1343 const MDeformVert *dvert,
1344 const int defgrp_index,
1345 float (*vertexCos)[3],
1346 int numVerts)
1347{
1348
1349 DerivedMesh *ss_mesh = nullptr;
1351
1352 /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
1353 if (smd->target == ob) {
1354 smd->target = nullptr;
1355 }
1356 if (smd->auxTarget == ob) {
1357 smd->auxTarget = nullptr;
1358 }
1359
1360 /* Configure Shrinkwrap calc data */
1361 calc.smd = smd;
1362 calc.ob = ob;
1363 calc.numVerts = numVerts;
1364 calc.vertexCos = vertexCos;
1365 calc.dvert = dvert;
1366 calc.vgroup = defgrp_index;
1368
1369 if (smd->target != nullptr) {
1370 Object *ob_target = DEG_get_evaluated(ctx->depsgraph, smd->target);
1372
1373 /* TODO: there might be several "bugs" with non-uniform scales matrices
1374 * because it will no longer be nearest surface, not sphere projection
1375 * because space has been deformed */
1376 BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target);
1377
1378 /* TODO: smd->keepDist is in global units.. must change to local */
1379 calc.keepDist = smd->keepDist;
1380 }
1382
1383 if (mesh != nullptr && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
1384 /* Setup arrays to get vertex positions, normals and deform weights */
1385 calc.vert_positions = reinterpret_cast<float(*)[3]>(mesh->vert_positions_for_write().data());
1386 calc.vert_normals = mesh->vert_normals();
1387
1388 /* Using vertices positions/normals as if a subsurface was applied */
1389 if (smd->subsurfLevels) {
1390 SubsurfModifierData ssmd = {{nullptr}};
1391 ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
1392 ssmd.levels = smd->subsurfLevels; /* levels */
1393
1394 /* TODO: to be moved to Mesh once we are done with changes in subsurf code. */
1396
1398 dm,
1399 &ssmd,
1400 scene,
1401 nullptr,
1403
1404 if (ss_mesh) {
1405 calc.vert_positions = reinterpret_cast<float(*)[3]>(ss_mesh->getVertArray(ss_mesh));
1406 if (calc.vert_positions) {
1407 /* TRICKY: this code assumes subsurface will have the transformed original vertices
1408 * in their original order at the end of the vert array. */
1409 calc.vert_positions = calc.vert_positions + ss_mesh->getNumVerts(ss_mesh) -
1410 dm->getNumVerts(dm);
1411 }
1412 }
1413
1414 /* Just to make sure we are not leaving any memory behind */
1415 BLI_assert(ssmd.emCache == nullptr);
1416 BLI_assert(ssmd.mCache == nullptr);
1417
1418 dm->release(dm);
1419 }
1420 }
1421
1422 /* Projecting target defined - lets work! */
1424
1425 if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) {
1426 calc.tree = &tree;
1427
1428 switch (smd->shrinkType) {
1432 break;
1433
1435 TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
1436 break;
1437
1439 TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex);
1440 break;
1441 }
1442
1444 }
1445
1446 /* free memory */
1447 if (ss_mesh) {
1448 ss_mesh->release(ss_mesh);
1449 }
1450}
1451
1453 Object &object,
1455 const blender::Span<MDeformVert> dvert,
1456 const int defgrp_index,
1458{
1459 using namespace blender::bke;
1460
1462 /* Convert params struct to use the same struct and function used with meshes. */
1464 smd.target = params.target;
1465 smd.auxTarget = params.aux_target;
1466 smd.keepDist = params.keep_distance;
1467 smd.shrinkType = params.shrink_type;
1468 smd.shrinkOpts = params.shrink_options;
1469 smd.shrinkMode = params.shrink_mode;
1470 smd.projLimit = params.projection_limit;
1471 smd.projAxis = params.projection_axis;
1472
1473 /* Configure Shrinkwrap calc data. */
1474 calc.smd = &smd;
1475 calc.ob = &object;
1476 calc.numVerts = int(positions.size());
1477 calc.vertexCos = reinterpret_cast<float(*)[3]>(positions.data());
1478 calc.dvert = dvert.is_empty() ? nullptr : dvert.data();
1479 calc.vgroup = defgrp_index;
1480 calc.invert_vgroup = params.invert_vertex_weights;
1481
1482 BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, &object, params.target);
1483 calc.keepDist = params.keep_distance;
1484 calc.tree = &tree;
1485
1486 switch (params.shrink_type) {
1487 case MOD_SHRINKWRAP_NEAREST_SURFACE:
1488 case MOD_SHRINKWRAP_TARGET_PROJECT:
1489 TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), gpdeform_surface);
1490 break;
1491
1492 case MOD_SHRINKWRAP_PROJECT:
1493 TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), gpdeform_project);
1494 break;
1495
1496 case MOD_SHRINKWRAP_NEAREST_VERTEX:
1497 TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), gpdeform_vertex);
1498 break;
1499 }
1500}
1501
1503 Scene *scene,
1504 Object *ob_source,
1505 Object *ob_target)
1506{
1507 ShrinkwrapModifierData ssmd = {{nullptr}};
1508 ModifierEvalContext ctx = {depsgraph, ob_source, ModifierApplyFlag(0)};
1509
1510 ssmd.target = ob_target;
1513 ssmd.keepDist = 0.0f;
1514
1515 Mesh *src_me = static_cast<Mesh *>(ob_source->data);
1516
1518 &ssmd,
1519 &ctx,
1520 scene,
1521 ob_source,
1522 src_me,
1523 nullptr,
1524 -1,
1525 reinterpret_cast<float(*)[3]>(src_me->vert_positions_for_write().data()),
1526 src_me->verts_num);
1527 src_me->tag_positions_changed();
1528}
1529
1530void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
1531{
1532 ShrinkwrapModifierData ssmd = {{nullptr}};
1533
1534 ssmd.target = ob_target;
1538 ssmd.keepDist = 0.0f;
1539
1540 /* Tolerance value to prevent artifacts on sharp edges of a mesh.
1541 * This constant and based on experimenting with different values. */
1542 const float projLimitTolerance = 5.0f;
1543 ssmd.projLimit = target_me->remesh_voxel_size * projLimitTolerance;
1544
1546
1547 calc.smd = &ssmd;
1548 calc.numVerts = src_me->verts_num;
1549 calc.vertexCos = reinterpret_cast<float(*)[3]>(src_me->vert_positions_for_write().data());
1550 calc.vert_normals = src_me->vert_normals();
1551 calc.vgroup = -1;
1552 calc.target = target_me;
1553 calc.keepDist = ssmd.keepDist;
1554 calc.vert_positions = reinterpret_cast<float(*)[3]>(src_me->vert_positions_for_write().data());
1555 BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target);
1556
1558 if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) {
1559 calc.tree = &tree;
1560 TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
1562 }
1563
1564 src_me->tag_positions_changed();
1565}
support for deformation groups and hooks.
float BKE_defvert_array_find_weight_safe(const MDeformVert *dvert, int index, int defgroup, bool invert)
Definition deform.cc:769
DerivedMesh * CDDM_from_mesh(Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
ModifierApplyFlag
#define NULL_BVHTreeNearest
#define NULL_ShrinkwrapCalcData
SubsurfFlags
@ SUBSURF_IN_EDIT_MODE
DerivedMesh * subsurf_make_derived_from_derived(DerivedMesh *dm, SubsurfModifierData *smd, const Scene *scene, float(*vertCos)[3], SubsurfFlags flags)
#define BLI_assert(a)
Definition BLI_assert.h:46
@ BVH_NEAREST_OPTIMAL_ORDER
#define BVH_RAYCAST_DIST_MAX
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
int BLI_bvhtree_find_nearest_ex(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata, int flag)
MINLINE float signf(float f)
#define M_SQRT2
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 closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
float mat4_to_scale(const float mat[4][4])
void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3])
void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3])
void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3])
void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3])
#define BLI_SPACE_TRANSFORM_SETUP(data, local, target)
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta, Newton3D_JacobianFunc func_jacobian, Newton3D_CorrectionFunc func_correction, void *userdata, float epsilon, int max_iterations, bool trace, const float x_init[3], float result[3])
Solve a generic f(x) = 0 equation using Newton's method.
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
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 void sub_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[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 void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void add_v2_fl(float r[2], float f)
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE float len_manhattan_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
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
Utility defines for timing/benchmarks.
#define CLAMP(a, b, c)
#define UNPACK3(a)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ME_CC_SUBSURF
@ MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS
@ MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS
@ MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS
@ MOD_SHRINKWRAP_PROJECT_OVER_NORMAL
#define MOD_SHRINKWRAP_CULL_TARGET_MASK
@ MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR
@ MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE
@ MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR
@ MOD_SHRINKWRAP_CULL_TARGET_BACKFACE
@ MOD_SHRINKWRAP_INVERT_VGROUP
@ MOD_SHRINKWRAP_INVERT_CULL_TARGET
@ MOD_SHRINKWRAP_TARGET_PROJECT
@ MOD_SHRINKWRAP_NEAREST_VERTEX
@ MOD_SHRINKWRAP_PROJECT
@ MOD_SHRINKWRAP_NEAREST_SURFACE
@ MOD_SHRINKWRAP_ON_SURFACE
@ MOD_SHRINKWRAP_OUTSIDE
@ MOD_SHRINKWRAP_INSIDE
@ MOD_SHRINKWRAP_ABOVE_SURFACE
@ MOD_SHRINKWRAP_OUTSIDE_SURFACE
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
switch((BMIterType) itype)
BMesh const char void * data
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
long long int int64_t
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static T sum(const btAlignedObjectArray< T > &items)
const T * data() const
Definition BLI_array.hh:301
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T * data() const
Definition BLI_span.hh:539
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
CCL_NAMESPACE_BEGIN struct Options options
#define fabsf(x)
#define sqrtf(x)
KDTree_3d * tree
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define printf(...)
#define fixed
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int3 corner_tri_get_real_edges(Span< int2 > edges, Span< int > corner_verts, Span< int > corner_edges, const int3 &corner_tri)
static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, MutableSpan< int8_t > status, int index, const float edge_dir[3], signed char side)
const ShrinkwrapBoundaryData & boundary_cache_ensure(const Mesh &mesh)
static ShrinkwrapBoundaryData shrinkwrap_build_boundary_data(const Mesh &mesh)
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
static void target_project_edge(const ShrinkwrapTreeData *tree, int index, const float co[3], BVHTreeNearest *nearest, int eidx)
static void target_project_tri_clamp(float x[3])
static bool target_project_solve_point_tri(const float *vtri_co[3], const float vtri_no[3][3], const float point_co[3], const float hit_co[3], float hit_dist_sq, float r_hit_co[3], float r_hit_no[3])
void BKE_shrinkwrap_snap_point_to_surface(const ShrinkwrapTreeData *tree, const SpaceTransform *transform, int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist, const float point_co[3], float r_point_co[3])
static void mesh_corner_tris_target_project(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *)
static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
static bool update_hit(BVHTreeNearest *nearest, int index, const float co[3], const float hit_co[3], const float hit_no[3])
static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap)
bool BKE_shrinkwrap_project_normal(char options, const float vert[3], const float dir[3], const float ray_radius, const SpaceTransform *transf, ShrinkwrapTreeData *tree, BVHTreeRayHit *hit)
static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3])
static void shrinkwrap_calc_nearest_vertex_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
void BKE_shrinkwrap_mesh_nearest_surface_deform(Depsgraph *depsgraph, Scene *scene, Object *ob_source, Object *ob_target)
static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
#define TIMEIT_BENCH(expr, id)
Definition shrinkwrap.cc:48
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
Definition shrinkwrap.cc:88
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, const ModifierEvalContext *ctx, Scene *scene, Object *ob, Mesh *mesh, const MDeformVert *dvert, const int defgrp_index, float(*vertexCos)[3], int numVerts)
static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3])
void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree, const SpaceTransform *transform, int corner_tri_idx, const float hit_co[3], const float hit_no[3], float r_no[3])
bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
Definition shrinkwrap.cc:95
void shrinkwrapParams_deform(const ShrinkwrapParams &params, Object &object, ShrinkwrapTreeData &tree, const blender::Span< MDeformVert > dvert, const int defgrp_index, const blender::MutableSpan< blender::float3 > positions)
static bool target_project_tri_correct(void *, const float x[3], float step[3], float x_next[3])
void BKE_shrinkwrap_find_nearest_surface(ShrinkwrapTreeData *tree, BVHTreeNearest *nearest, float co[3], int type)
static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
#define FLT_MAX
Definition stdcycles.h:14
float *(* getVertArray)(DerivedMesh *dm)
float remesh_voxel_size
int verts_num
SpaceTransform * local2aux
Definition shrinkwrap.cc:85
ShrinkwrapTreeData * tree
Definition shrinkwrap.cc:81
ShrinkwrapCalcData * calc
Definition shrinkwrap.cc:79
ShrinkwrapTreeData * aux_tree
Definition shrinkwrap.cc:82
float(* vertexCos)[3]
Definition shrinkwrap.cc:62
SpaceTransform local2target
Definition shrinkwrap.cc:70
float(* vert_positions)[3]
Definition shrinkwrap.cc:59
blender::Span< blender::float3 > vert_normals
Definition shrinkwrap.cc:60
const MDeformVert * dvert
Definition shrinkwrap.cc:65
ShrinkwrapTreeData * tree
Definition shrinkwrap.cc:71
ShrinkwrapModifierData * smd
Definition shrinkwrap.cc:55
const float ** vtri_co
const float * point_co
const float(* vtri_no)[3]
size_t userdata_chunk_size
Definition BLI_task.h:164
BVHTree_NearestPointCallback nearest_callback
i
Definition text_draw.cc:230