Blender V4.3
mesh_remap.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <climits>
12
13#include "CLG_log.h"
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_array.hh"
18#include "BLI_astar.h"
19#include "BLI_bit_vector.hh"
20#include "BLI_math_geom.h"
21#include "BLI_math_matrix.h"
22#include "BLI_math_solvers.h"
23#include "BLI_math_statistics.h"
24#include "BLI_math_vector.h"
25#include "BLI_memarena.h"
26#include "BLI_polyfill_2d.h"
27#include "BLI_rand.h"
28#include "BLI_utildefines.h"
29
30#include "BKE_bvhutils.hh"
31#include "BKE_customdata.hh"
32#include "BKE_mesh.hh"
33#include "BKE_mesh_mapping.hh"
34#include "BKE_mesh_remap.hh" /* own include */
35#include "BKE_mesh_runtime.hh"
36
37#include "BLI_strict_flags.h" /* Keep last. */
38
39static CLG_LogRef LOG = {"bke.mesh"};
40
41/* -------------------------------------------------------------------- */
46 BVHTreeNearest *nearest,
47 const float co[3],
48 const float max_dist_sq,
49 float *r_hit_dist)
50{
51 /* Use local proximity heuristics (to reduce the nearest search). */
52 if (nearest->index != -1) {
53 nearest->dist_sq = len_squared_v3v3(co, nearest->co);
54 if (nearest->dist_sq > max_dist_sq) {
55 /* The previous valid index is too far away and not valid for this check. */
56 nearest->dist_sq = max_dist_sq;
57 nearest->index = -1;
58 }
59 }
60 else {
61 nearest->dist_sq = max_dist_sq;
62 }
63 /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */
64 BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata);
65
66 if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) {
67 *r_hit_dist = sqrtf(nearest->dist_sq);
68 return true;
69 }
70
71 return false;
72}
73
75 BVHTreeRayHit *rayhit,
76 const float co[3],
77 const float no[3],
78 const float radius,
79 const float max_dist,
80 float *r_hit_dist)
81{
82 BVHTreeRayHit rayhit_tmp;
83 float inv_no[3];
84
85 rayhit->index = -1;
86 rayhit->dist = max_dist;
88 treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata);
89
90 /* Also cast in the other direction! */
91 rayhit_tmp = *rayhit;
92 negate_v3_v3(inv_no, no);
94 treedata->tree, co, inv_no, radius, &rayhit_tmp, treedata->raycast_callback, treedata);
95 if (rayhit_tmp.dist < rayhit->dist) {
96 *rayhit = rayhit_tmp;
97 }
98
99 if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) {
100 *r_hit_dist = rayhit->dist;
101 return true;
102 }
103
104 return false;
105}
106
109/* -------------------------------------------------------------------- */
116 const float (*vert_positions_dst)[3],
117 const int numverts_dst,
118 const Mesh *me_src)
119{
120 BVHTreeFromMesh treedata = {nullptr};
121 BVHTreeNearest nearest = {0};
122 float hit_dist;
123
124 float result = 0.0f;
125 int i;
126
127 BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
128 nearest.index = -1;
129
130 for (i = 0; i < numverts_dst; i++) {
131 float tmp_co[3];
132
133 copy_v3_v3(tmp_co, vert_positions_dst[i]);
134
135 /* Convert the vertex to tree coordinates, if needed. */
136 if (space_transform) {
137 BLI_space_transform_apply(space_transform, tmp_co);
138 }
139
140 if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, FLT_MAX, &hit_dist)) {
141 result += 1.0f / (hit_dist + 1.0f);
142 }
143 else {
144 /* No source for this dest vertex! */
145 result += 1e-18f;
146 }
147 }
148
149 result = (float(numverts_dst) / result) - 1.0f;
150
151#if 0
152 printf("%s: Computed difference between meshes (the lower the better): %f\n", __func__, result);
153#endif
154
155 return result;
156}
157
158/* This helper computes the eigen values & vectors for
159 * covariance matrix of all given vertices coordinates.
160 *
161 * Those vectors define the 'average ellipsoid' of the mesh (i.e. the 'best fitting' ellipsoid
162 * containing 50% of the vertices).
163 *
164 * Note that it will not perform fantastic in case two or more eigen values are equal
165 * (e.g. a cylinder or parallelepiped with a square section give two identical eigenvalues,
166 * a sphere or tetrahedron give three identical ones, etc.), since you cannot really define all
167 * axes in those cases. We default to dummy generated orthogonal vectors in this case,
168 * instead of using eigen vectors.
169 */
170static void mesh_calc_eigen_matrix(const float (*positions)[3],
171 const float (*vcos)[3],
172 const int numverts,
173 float r_mat[4][4])
174{
175 float center[3], covmat[3][3];
176 float eigen_val[3], eigen_vec[3][3];
177 float(*cos)[3] = nullptr;
178
179 bool eigen_success;
180 int i;
181
182 if (positions) {
183 cos = static_cast<float(*)[3]>(MEM_mallocN(sizeof(*cos) * size_t(numverts), __func__));
184 memcpy(cos, positions, sizeof(float[3]) * size_t(numverts));
185 /* TODO(sergey): For until we officially drop all compilers which
186 * doesn't handle casting correct we use workaround to avoid explicit
187 * cast here.
188 */
189 vcos = static_cast<const float(*)[3]>((void *)cos);
190 }
191 unit_m4(r_mat);
192
193 /* NOTE: here we apply sample correction to covariance matrix, since we consider the vertices
194 * as a sample of the whole 'surface' population of our mesh. */
195 BLI_covariance_m3_v3n(vcos, numverts, true, covmat, center);
196
197 if (cos) {
198 MEM_freeN(cos);
199 }
200
201 eigen_success = BLI_eigen_solve_selfadjoint_m3((const float(*)[3])covmat, eigen_val, eigen_vec);
202 BLI_assert(eigen_success);
203 UNUSED_VARS_NDEBUG(eigen_success);
204
205 /* Special handling of cases where some eigen values are (nearly) identical. */
206 if (compare_ff_relative(eigen_val[0], eigen_val[1], FLT_EPSILON, 64)) {
207 if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
208 /* No preferred direction, that set of vertices has a spherical average,
209 * so we simply returned scaled/translated identity matrix (with no rotation). */
210 unit_m3(eigen_vec);
211 }
212 else {
213 /* Ellipsoid defined by eigen values/vectors has a spherical section,
214 * we can only define one axis from eigen_vec[2] (two others computed eigen vecs
215 * are not so nice for us here, they tend to 'randomly' rotate around valid one).
216 * Note that eigen vectors as returned by BLI_eigen_solve_selfadjoint_m3() are normalized. */
217 ortho_basis_v3v3_v3(eigen_vec[0], eigen_vec[1], eigen_vec[2]);
218 }
219 }
220 else if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
221 /* Same as above, but with eigen_vec[1] as valid axis. */
222 ortho_basis_v3v3_v3(eigen_vec[2], eigen_vec[0], eigen_vec[1]);
223 }
224 else if (compare_ff_relative(eigen_val[1], eigen_val[2], FLT_EPSILON, 64)) {
225 /* Same as above, but with eigen_vec[0] as valid axis. */
226 ortho_basis_v3v3_v3(eigen_vec[1], eigen_vec[2], eigen_vec[0]);
227 }
228
229 for (i = 0; i < 3; i++) {
230 float evi = eigen_val[i];
231
232 /* Protect against 1D/2D degenerated cases! */
233 /* NOTE: not sure why we need square root of eigen values here
234 * (which are equivalent to singular values, as far as I have understood),
235 * but it seems to heavily reduce (if not completely nullify)
236 * the error due to non-uniform scalings... */
237 evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi);
238 mul_v3_fl(eigen_vec[i], evi);
239 }
240
241 copy_m4_m3(r_mat, eigen_vec);
242 copy_v3_v3(r_mat[3], center);
243}
244
245void BKE_mesh_remap_find_best_match_from_mesh(const float (*vert_positions_dst)[3],
246 const int numverts_dst,
247 const Mesh *me_src,
248 SpaceTransform *r_space_transform)
249{
250 /* Note that those are done so that we successively get actual mirror matrix
251 * (by multiplication of columns). */
252 const float mirrors[][3] = {
253 {-1.0f, 1.0f, 1.0f}, /* -> -1, 1, 1 */
254 {1.0f, -1.0f, 1.0f}, /* -> -1, -1, 1 */
255 {1.0f, 1.0f, -1.0f}, /* -> -1, -1, -1 */
256 {1.0f, -1.0f, 1.0f}, /* -> -1, 1, -1 */
257 {-1.0f, 1.0f, 1.0f}, /* -> 1, 1, -1 */
258 {1.0f, -1.0f, 1.0f}, /* -> 1, -1, -1 */
259 {1.0f, 1.0f, -1.0f}, /* -> 1, -1, 1 */
260 {0.0f, 0.0f, 0.0f},
261 };
262 const float(*mirr)[3];
263
264 float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
265 float best_match = FLT_MAX, match;
266
267 const int numverts_src = me_src->verts_num;
268 const blender::Span<blender::float3> positions_src = me_src->vert_positions();
270 nullptr, reinterpret_cast<const float(*)[3]>(positions_src.data()), numverts_src, mat_src);
271 mesh_calc_eigen_matrix(vert_positions_dst, nullptr, numverts_dst, mat_dst);
272
273 BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
275 r_space_transform, vert_positions_dst, numverts_dst, me_src);
276 best_match = match;
277 copy_m4_m4(best_mat_dst, mat_dst);
278
279 /* And now, we have to check the other sixth possible mirrored versions... */
280 for (mirr = mirrors; (*mirr)[0]; mirr++) {
281 mul_v3_fl(mat_dst[0], (*mirr)[0]);
282 mul_v3_fl(mat_dst[1], (*mirr)[1]);
283 mul_v3_fl(mat_dst[2], (*mirr)[2]);
284
285 BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
287 r_space_transform, vert_positions_dst, numverts_dst, me_src);
288 if (match < best_match) {
289 best_match = match;
290 copy_m4_m4(best_mat_dst, mat_dst);
291 }
292 }
293
294 BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src);
295}
296
299/* -------------------------------------------------------------------- */
303void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
304{
306
308
309 map->items = static_cast<MeshPairRemapItem *>(
310 BLI_memarena_alloc(mem, sizeof(*map->items) * size_t(items_num)));
311 map->items_num = items_num;
312
313 map->mem = mem;
314}
315
317{
318 if (map->mem) {
319 BLI_memarena_free((MemArena *)map->mem);
320 }
321
322 map->items_num = 0;
323 map->items = nullptr;
324 map->mem = nullptr;
325}
326
328 const int index,
329 const float /*hit_dist*/,
330 const int island,
331 const int sources_num,
332 const int *indices_src,
333 const float *weights_src)
334{
335 MeshPairRemapItem *mapit = &map->items[index];
336 MemArena *mem = map->mem;
337
338 if (sources_num) {
339 mapit->sources_num = sources_num;
340 mapit->indices_src = static_cast<int *>(
341 BLI_memarena_alloc(mem, sizeof(*mapit->indices_src) * size_t(sources_num)));
342 memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * size_t(sources_num));
343 mapit->weights_src = static_cast<float *>(
344 BLI_memarena_alloc(mem, sizeof(*mapit->weights_src) * size_t(sources_num)));
345 memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * size_t(sources_num));
346 }
347 else {
348 mapit->sources_num = 0;
349 mapit->indices_src = nullptr;
350 mapit->weights_src = nullptr;
351 }
352 // mapit->hit_dist = hit_dist;
353 mapit->island = island;
354}
355
357{
358 mesh_remap_item_define(map, index, FLT_MAX, 0, 0, nullptr, nullptr);
359}
360
362 const blender::Span<int> corner_verts,
363 const blender::Span<blender::float3> positions_src,
364 const float point[3],
365 size_t *buff_size,
366 float (**vcos)[3],
367 const bool use_loops,
368 int **indices,
369 float **weights,
370 const bool do_weights,
371 int *r_closest_index)
372{
373 float(*vco)[3];
374 float ref_dist_sq = FLT_MAX;
375 int *index;
376 const int sources_num = int(face.size());
377 int i;
378
379 if (size_t(sources_num) > *buff_size) {
380 *buff_size = size_t(sources_num);
381 *vcos = static_cast<float(*)[3]>(MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size));
382 *indices = static_cast<int *>(MEM_reallocN(*indices, sizeof(**indices) * *buff_size));
383 if (do_weights) {
384 *weights = static_cast<float *>(MEM_reallocN(*weights, sizeof(**weights) * *buff_size));
385 }
386 }
387
388 for (i = 0, vco = *vcos, index = *indices; i < sources_num; i++, vco++, index++) {
389 const int vert = corner_verts[face[i]];
390 *index = use_loops ? int(face[i]) : vert;
391 copy_v3_v3(*vco, positions_src[vert]);
392 if (r_closest_index) {
393 /* Find closest vert/loop in this case. */
394 const float dist_sq = len_squared_v3v3(point, *vco);
395 if (dist_sq < ref_dist_sq) {
396 ref_dist_sq = dist_sq;
397 *r_closest_index = *index;
398 }
399 }
400 }
401
402 if (do_weights) {
403 interp_weights_poly_v3(*weights, *vcos, sources_num, point);
404 }
405
406 return sources_num;
407}
408
412 float factor;
416 float hit_dist;
418 float hit_point[3];
419};
420
438#define MREMAP_RAYCAST_APPROXIMATE_NR 3
440#define MREMAP_RAYCAST_APPROXIMATE_FAC 5.0f
441
442/* min 16 rays/face, max 400. */
443#define MREMAP_RAYCAST_TRI_SAMPLES_MIN 4
444#define MREMAP_RAYCAST_TRI_SAMPLES_MAX 20
445
446/* Will be enough in 99% of cases. */
447#define MREMAP_DEFAULT_BUFSIZE 32
448
450 const SpaceTransform *space_transform,
451 const float max_dist,
452 const float ray_radius,
453 const float (*vert_positions_dst)[3],
454 const int numverts_dst,
455 const Mesh *me_src,
456 Mesh *me_dst,
457 MeshPairRemap *r_map)
458{
459 const float full_weight = 1.0f;
460 const float max_dist_sq = max_dist * max_dist;
461 int i;
462
464
465 BKE_mesh_remap_init(r_map, numverts_dst);
466
467 if (mode == MREMAP_MODE_TOPOLOGY) {
468 BLI_assert(numverts_dst == me_src->verts_num);
469 for (i = 0; i < numverts_dst; i++) {
470 mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
471 }
472 }
473 else {
474 BVHTreeFromMesh treedata = {nullptr};
475 BVHTreeNearest nearest = {0};
476 BVHTreeRayHit rayhit = {0};
477 float hit_dist;
478 float tmp_co[3], tmp_no[3];
479
480 if (mode == MREMAP_MODE_VERT_NEAREST) {
481 BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
482 nearest.index = -1;
483
484 for (i = 0; i < numverts_dst; i++) {
485 copy_v3_v3(tmp_co, vert_positions_dst[i]);
486
487 /* Convert the vertex to tree coordinates, if needed. */
488 if (space_transform) {
489 BLI_space_transform_apply(space_transform, tmp_co);
490 }
491
492 if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
493 {
494 mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
495 }
496 else {
497 /* No source for this dest vertex! */
499 }
500 }
501 }
503 const blender::Span<blender::int2> edges_src = me_src->edges();
504 const blender::Span<blender::float3> positions_src = me_src->vert_positions();
505
506 BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
507 nearest.index = -1;
508
509 for (i = 0; i < numverts_dst; i++) {
510 copy_v3_v3(tmp_co, vert_positions_dst[i]);
511
512 /* Convert the vertex to tree coordinates, if needed. */
513 if (space_transform) {
514 BLI_space_transform_apply(space_transform, tmp_co);
515 }
516
517 if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
518 {
519 const blender::int2 &edge = edges_src[nearest.index];
520 const float *v1cos = positions_src[edge[0]];
521 const float *v2cos = positions_src[edge[1]];
522
523 if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) {
524 const float dist_v1 = len_squared_v3v3(tmp_co, v1cos);
525 const float dist_v2 = len_squared_v3v3(tmp_co, v2cos);
526 const int index = (dist_v1 > dist_v2) ? edge[1] : edge[0];
527 mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
528 }
529 else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) {
530 int indices[2];
531 float weights[2];
532
533 indices[0] = edge[0];
534 indices[1] = edge[1];
535
536 /* Weight is inverse of point factor here... */
537 weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos);
538 CLAMP(weights[0], 0.0f, 1.0f);
539 weights[1] = 1.0f - weights[0];
540
541 mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights);
542 }
543 }
544 else {
545 /* No source for this dest vertex! */
547 }
548 }
549 }
550 else if (ELEM(mode,
554 {
555 const blender::OffsetIndices faces_src = me_src->faces();
556 const blender::Span<int> corner_verts_src = me_src->corner_verts();
557 const blender::Span<blender::float3> positions_src = me_src->vert_positions();
558 const blender::Span<blender::float3> vert_normals_dst = me_dst->vert_normals();
559 const blender::Span<int> tri_faces = me_src->corner_tri_faces();
560
561 size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
562 float(*vcos)[3] = static_cast<float(*)[3]>(
563 MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__));
564 int *indices = static_cast<int *>(MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__));
565 float *weights = static_cast<float *>(
566 MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__));
567
569
571 for (i = 0; i < numverts_dst; i++) {
572 copy_v3_v3(tmp_co, vert_positions_dst[i]);
573 copy_v3_v3(tmp_no, vert_normals_dst[i]);
574
575 /* Convert the vertex to tree coordinates, if needed. */
576 if (space_transform) {
577 BLI_space_transform_apply(space_transform, tmp_co);
578 BLI_space_transform_apply_normal(space_transform, tmp_no);
579 }
580
582 &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist))
583 {
584 const int face_index = tri_faces[rayhit.index];
585 const int sources_num = mesh_remap_interp_face_data_get(faces_src[face_index],
586 corner_verts_src,
587 positions_src,
588 rayhit.co,
589 &tmp_buff_size,
590 &vcos,
591 false,
592 &indices,
593 &weights,
594 true,
595 nullptr);
596
597 mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
598 }
599 else {
600 /* No source for this dest vertex! */
602 }
603 }
604 }
605 else {
606 nearest.index = -1;
607
608 for (i = 0; i < numverts_dst; i++) {
609 copy_v3_v3(tmp_co, vert_positions_dst[i]);
610
611 /* Convert the vertex to tree coordinates, if needed. */
612 if (space_transform) {
613 BLI_space_transform_apply(space_transform, tmp_co);
614 }
615
617 &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
618 {
619 const int face_index = tri_faces[nearest.index];
620
621 if (mode == MREMAP_MODE_VERT_FACE_NEAREST) {
622 int index;
623 mesh_remap_interp_face_data_get(faces_src[face_index],
624 corner_verts_src,
625 positions_src,
626 nearest.co,
627 &tmp_buff_size,
628 &vcos,
629 false,
630 &indices,
631 &weights,
632 false,
633 &index);
634
635 mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
636 }
637 else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) {
638 const int sources_num = mesh_remap_interp_face_data_get(faces_src[face_index],
639 corner_verts_src,
640 positions_src,
641 nearest.co,
642 &tmp_buff_size,
643 &vcos,
644 false,
645 &indices,
646 &weights,
647 true,
648 nullptr);
649
650 mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
651 }
652 }
653 else {
654 /* No source for this dest vertex! */
656 }
657 }
658 }
659
660 MEM_freeN(vcos);
661 MEM_freeN(indices);
662 MEM_freeN(weights);
663 }
664 else {
665 CLOG_WARN(&LOG, "Unsupported mesh-to-mesh vertex mapping mode (%d)!", mode);
666 memset(r_map->items, 0, sizeof(*r_map->items) * size_t(numverts_dst));
667 }
668
669 free_bvhtree_from_mesh(&treedata);
670 }
671}
672
674 const SpaceTransform *space_transform,
675 const float max_dist,
676 const float ray_radius,
677 const float (*vert_positions_dst)[3],
678 const int numverts_dst,
679 const blender::int2 *edges_dst,
680 const int numedges_dst,
681 const Mesh *me_src,
682 Mesh *me_dst,
683 MeshPairRemap *r_map)
684{
685 using namespace blender;
686 const float full_weight = 1.0f;
687 const float max_dist_sq = max_dist * max_dist;
688 int i;
689
691
692 BKE_mesh_remap_init(r_map, numedges_dst);
693
694 if (mode == MREMAP_MODE_TOPOLOGY) {
695 BLI_assert(numedges_dst == me_src->edges_num);
696 for (i = 0; i < numedges_dst; i++) {
697 mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
698 }
699 }
700 else {
701 BVHTreeFromMesh treedata = {nullptr};
702 BVHTreeNearest nearest = {0};
703 BVHTreeRayHit rayhit = {0};
704 float hit_dist;
705 float tmp_co[3], tmp_no[3];
706
707 if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
708 const int num_verts_src = me_src->verts_num;
709 const blender::Span<blender::int2> edges_src = me_src->edges();
710 const blender::Span<blender::float3> positions_src = me_src->vert_positions();
711
712 struct HitData {
713 float hit_dist;
714 int index;
715 };
716 HitData *v_dst_to_src_map = static_cast<HitData *>(
717 MEM_mallocN(sizeof(*v_dst_to_src_map) * size_t(numverts_dst), __func__));
718
719 for (i = 0; i < numverts_dst; i++) {
720 v_dst_to_src_map[i].hit_dist = -1.0f;
721 }
722
723 Array<int> vert_to_edge_src_offsets;
724 Array<int> vert_to_edge_src_indices;
725 const GroupedSpan<int> vert_to_edge_src_map = bke::mesh::build_vert_to_edge_map(
726 edges_src, num_verts_src, vert_to_edge_src_offsets, vert_to_edge_src_indices);
727
728 BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
729 nearest.index = -1;
730
731 for (i = 0; i < numedges_dst; i++) {
732 const blender::int2 &e_dst = edges_dst[i];
733 float best_totdist = FLT_MAX;
734 int best_eidx_src = -1;
735 int j = 2;
736
737 while (j--) {
738 const int vidx_dst = j ? e_dst[0] : e_dst[1];
739
740 /* Compute closest verts only once! */
741 if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
742 copy_v3_v3(tmp_co, vert_positions_dst[vidx_dst]);
743
744 /* Convert the vertex to tree coordinates, if needed. */
745 if (space_transform) {
746 BLI_space_transform_apply(space_transform, tmp_co);
747 }
748
750 &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
751 {
752 v_dst_to_src_map[vidx_dst].hit_dist = hit_dist;
753 v_dst_to_src_map[vidx_dst].index = nearest.index;
754 }
755 else {
756 /* No source for this dest vert! */
757 v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX;
758 }
759 }
760 }
761
762 /* Now, check all source edges of closest sources vertices,
763 * and select the one giving the smallest total verts-to-verts distance. */
764 for (j = 2; j--;) {
765 const int vidx_dst = j ? e_dst[0] : e_dst[1];
766 const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist;
767 const int vidx_src = v_dst_to_src_map[vidx_dst].index;
768 const int *eidx_src;
769 int k;
770
771 if (vidx_src < 0) {
772 continue;
773 }
774
775 eidx_src = vert_to_edge_src_map[vidx_src].data();
776 k = int(vert_to_edge_src_map[vidx_src].size());
777
778 for (; k--; eidx_src++) {
779 const blender::int2 &edge_src = edges_src[*eidx_src];
780 const float *other_co_src =
781 positions_src[blender::bke::mesh::edge_other_vert(edge_src, vidx_src)];
782 const float *other_co_dst =
783 vert_positions_dst[blender::bke::mesh::edge_other_vert(e_dst, int(vidx_dst))];
784 const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst);
785
786 if (totdist < best_totdist) {
787 best_totdist = totdist;
788 best_eidx_src = *eidx_src;
789 }
790 }
791 }
792
793 if (best_eidx_src >= 0) {
794 const float *co1_src = positions_src[edges_src[best_eidx_src][0]];
795 const float *co2_src = positions_src[edges_src[best_eidx_src][1]];
796 const float *co1_dst = vert_positions_dst[e_dst[0]];
797 const float *co2_dst = vert_positions_dst[e_dst[1]];
798 float co_src[3], co_dst[3];
799
800 /* TODO: would need an isect_seg_seg_v3(), actually! */
801 const int isect_type = isect_line_line_v3(
802 co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst);
803 if (isect_type != 0) {
804 const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src);
805 const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst);
806 if (fac_src < 0.0f) {
807 copy_v3_v3(co_src, co1_src);
808 }
809 else if (fac_src > 1.0f) {
810 copy_v3_v3(co_src, co2_src);
811 }
812 if (fac_dst < 0.0f) {
813 copy_v3_v3(co_dst, co1_dst);
814 }
815 else if (fac_dst > 1.0f) {
816 copy_v3_v3(co_dst, co2_dst);
817 }
818 }
819 hit_dist = len_v3v3(co_dst, co_src);
820 mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
821 }
822 else {
823 /* No source for this dest edge! */
825 }
826 }
827
828 MEM_freeN(v_dst_to_src_map);
829 }
830 else if (mode == MREMAP_MODE_EDGE_NEAREST) {
831 BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
832 nearest.index = -1;
833
834 for (i = 0; i < numedges_dst; i++) {
835 interp_v3_v3v3(tmp_co,
836 vert_positions_dst[edges_dst[i][0]],
837 vert_positions_dst[edges_dst[i][1]],
838 0.5f);
839
840 /* Convert the vertex to tree coordinates, if needed. */
841 if (space_transform) {
842 BLI_space_transform_apply(space_transform, tmp_co);
843 }
844
845 if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
846 {
847 mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
848 }
849 else {
850 /* No source for this dest edge! */
852 }
853 }
854 }
855 else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
856 const blender::Span<blender::int2> edges_src = me_src->edges();
857 const blender::OffsetIndices faces_src = me_src->faces();
858 const blender::Span<int> corner_edges_src = me_src->corner_edges();
859 const blender::Span<blender::float3> positions_src = me_src->vert_positions();
860 const blender::Span<int> tri_faces = me_src->corner_tri_faces();
861
863
864 for (i = 0; i < numedges_dst; i++) {
865 interp_v3_v3v3(tmp_co,
866 vert_positions_dst[edges_dst[i][0]],
867 vert_positions_dst[edges_dst[i][1]],
868 0.5f);
869
870 /* Convert the vertex to tree coordinates, if needed. */
871 if (space_transform) {
872 BLI_space_transform_apply(space_transform, tmp_co);
873 }
874
875 if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
876 {
877 const int face_index = tri_faces[nearest.index];
878 const blender::IndexRange face_src = faces_src[face_index];
879 const int *corner_edge_src = &corner_edges_src[face_src.start()];
880 int nloops = int(face_src.size());
881 float best_dist_sq = FLT_MAX;
882 int best_eidx_src = -1;
883
884 for (; nloops--; corner_edge_src++) {
885 const blender::int2 &edge_src = edges_src[*corner_edge_src];
886 const float *co1_src = positions_src[edge_src[0]];
887 const float *co2_src = positions_src[edge_src[1]];
888 float co_src[3];
889 float dist_sq;
890
891 interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f);
892 dist_sq = len_squared_v3v3(tmp_co, co_src);
893 if (dist_sq < best_dist_sq) {
894 best_dist_sq = dist_sq;
895 best_eidx_src = *corner_edge_src;
896 }
897 }
898 if (best_eidx_src >= 0) {
899 mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
900 }
901 }
902 else {
903 /* No source for this dest edge! */
905 }
906 }
907 }
908 else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
909 const int num_rays_min = 5, num_rays_max = 100;
910 const int numedges_src = me_src->edges_num;
911
912 /* Subtleness - this one we can allocate only max number of cast rays per edges! */
913 int *indices = static_cast<int *>(
914 MEM_mallocN(sizeof(*indices) * size_t(min_ii(numedges_src, num_rays_max)), __func__));
915 /* Here it's simpler to just allocate for all edges :/ */
916 float *weights = static_cast<float *>(
917 MEM_mallocN(sizeof(*weights) * size_t(numedges_src), __func__));
918
919 BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
920
921 const blender::Span<blender::float3> vert_normals_dst = me_dst->vert_normals();
922
923 for (i = 0; i < numedges_dst; i++) {
924 /* For each dst edge, we sample some rays from it (interpolated from its vertices)
925 * and use their hits to interpolate from source edges. */
926 const blender::int2 &edge = edges_dst[i];
927 float v1_co[3], v2_co[3];
928 float v1_no[3], v2_no[3];
929
930 int grid_size;
931 float edge_dst_len;
932 float grid_step;
933
934 float totweights = 0.0f;
935 float hit_dist_accum = 0.0f;
936 int sources_num = 0;
937 int j;
938
939 copy_v3_v3(v1_co, vert_positions_dst[edge[0]]);
940 copy_v3_v3(v2_co, vert_positions_dst[edge[1]]);
941
942 copy_v3_v3(v1_no, vert_normals_dst[edge[0]]);
943 copy_v3_v3(v2_no, vert_normals_dst[edge[1]]);
944
945 /* We do our transform here, allows to interpolate from normals already in src space. */
946 if (space_transform) {
947 BLI_space_transform_apply(space_transform, v1_co);
948 BLI_space_transform_apply(space_transform, v2_co);
949 BLI_space_transform_apply_normal(space_transform, v1_no);
950 BLI_space_transform_apply_normal(space_transform, v2_no);
951 }
952
953 copy_vn_fl(weights, int(numedges_src), 0.0f);
954
955 /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
956 * with lower/upper bounds. */
957 edge_dst_len = len_v3v3(v1_co, v2_co);
958
959 grid_size = int((edge_dst_len / ray_radius) + 0.5f);
960 CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */
961
962 /* Not actual distance here, rather an interp fac... */
963 grid_step = 1.0f / float(grid_size);
964
965 /* And now we can cast all our rays, and see what we get! */
966 for (j = 0; j < grid_size; j++) {
967 const float fac = grid_step * float(j);
968
969 int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
970 float w = 1.0f;
971
972 interp_v3_v3v3(tmp_co, v1_co, v2_co, fac);
973 interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac);
974
975 while (n--) {
977 &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
978 {
979 weights[rayhit.index] += w;
980 totweights += w;
981 hit_dist_accum += hit_dist;
982 break;
983 }
984 /* Next iteration will get bigger radius but smaller weight! */
986 }
987 }
988 /* A sampling is valid (as in, its result can be considered as valid sources)
989 * only if at least half of the rays found a source! */
990 if (totweights > (float(grid_size) / 2.0f)) {
991 for (j = 0; j < int(numedges_src); j++) {
992 if (!weights[j]) {
993 continue;
994 }
995 /* NOTE: sources_num is always <= j! */
996 weights[sources_num] = weights[j] / totweights;
997 indices[sources_num] = j;
998 sources_num++;
999 }
1001 r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights);
1002 }
1003 else {
1004 /* No source for this dest edge! */
1006 }
1007 }
1008
1009 MEM_freeN(indices);
1010 MEM_freeN(weights);
1011 }
1012 else {
1013 CLOG_WARN(&LOG, "Unsupported mesh-to-mesh edge mapping mode (%d)!", mode);
1014 memset(r_map->items, 0, sizeof(*r_map->items) * size_t(numedges_dst));
1015 }
1016
1017 free_bvhtree_from_mesh(&treedata);
1018 }
1019}
1020
1021#define POLY_UNSET 0
1022#define POLY_CENTER_INIT 1
1023#define POLY_COMPLETE 2
1024
1026 MeshIslandStore *islands,
1027 const int island_index,
1028 BLI_AStarGraph *as_graph,
1029 const blender::Span<blender::float3> positions,
1030 const blender::OffsetIndices<int> faces,
1031 const blender::Span<int> corner_verts,
1032 const int edge_idx,
1033 BLI_bitmap *done_edges,
1034 const blender::GroupedSpan<int> edge_to_face_map,
1035 const bool is_edge_innercut,
1036 const int *face_island_index_map,
1037 float (*face_centers)[3],
1038 uchar *face_status)
1039{
1040 blender::Array<int, 16> face_island_indices(edge_to_face_map[edge_idx].size());
1041 int i, j;
1042
1043 for (i = 0; i < edge_to_face_map[edge_idx].size(); i++) {
1044 const int pidx = edge_to_face_map[edge_idx][i];
1045 const blender::IndexRange face = faces[pidx];
1046 const int pidx_isld = islands ? face_island_index_map[pidx] : pidx;
1047 void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1);
1048
1049 if (UNLIKELY(islands && (islands->items_to_islands[face.start()] != island_index))) {
1050 /* face not in current island, happens with border edges... */
1051 face_island_indices[i] = -1;
1052 continue;
1053 }
1054
1055 if (face_status[pidx_isld] == POLY_COMPLETE) {
1056 face_island_indices[i] = pidx_isld;
1057 continue;
1058 }
1059
1060 if (face_status[pidx_isld] == POLY_UNSET) {
1061 copy_v3_v3(face_centers[pidx_isld],
1062 blender::bke::mesh::face_center_calc(positions, corner_verts.slice(face)));
1063 BLI_astar_node_init(as_graph, pidx_isld, face_centers[pidx_isld]);
1064 face_status[pidx_isld] = POLY_CENTER_INIT;
1065 }
1066
1067 for (j = i; j--;) {
1068 float dist_cost;
1069 const int pidx_isld_other = face_island_indices[j];
1070
1071 if (pidx_isld_other == -1 || face_status[pidx_isld_other] == POLY_COMPLETE) {
1072 /* If the other face is complete, that link has already been added! */
1073 continue;
1074 }
1075 dist_cost = len_v3v3(face_centers[pidx_isld_other], face_centers[pidx_isld]);
1076 BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data);
1077 }
1078
1079 face_island_indices[i] = pidx_isld;
1080 }
1081
1082 BLI_BITMAP_ENABLE(done_edges, edge_idx);
1083}
1084
1086 const int island_index,
1087 const blender::Span<blender::float3> positions,
1088 const blender::GroupedSpan<int> edge_to_face_map,
1089 const int numedges,
1090 const blender::OffsetIndices<int> faces,
1091 const blender::Span<int> corner_verts,
1092 const blender::Span<int> corner_edges,
1093 BLI_AStarGraph *r_as_graph)
1094{
1095 MeshElemMap *island_face_map = islands ? islands->islands[island_index] : nullptr;
1096 MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : nullptr;
1097
1098 int *face_island_index_map = nullptr;
1099 BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__);
1100
1101 const int node_num = islands ? island_face_map->count : int(faces.size());
1102 uchar *face_status = static_cast<uchar *>(
1103 MEM_callocN(sizeof(*face_status) * size_t(node_num), __func__));
1104 float(*face_centers)[3];
1105
1106 int pidx_isld;
1107 int i;
1108
1109 BLI_astar_graph_init(r_as_graph, node_num, nullptr);
1110 /* face_centers is owned by graph memarena. */
1111 face_centers = static_cast<float(*)[3]>(
1112 BLI_memarena_calloc(r_as_graph->mem, sizeof(*face_centers) * size_t(node_num)));
1113
1114 if (islands) {
1115 /* face_island_index_map is owned by graph memarena. */
1116 face_island_index_map = static_cast<int *>(BLI_memarena_calloc(
1117 r_as_graph->mem, sizeof(*face_island_index_map) * size_t(faces.size())));
1118 for (i = island_face_map->count; i--;) {
1119 face_island_index_map[island_face_map->indices[i]] = i;
1120 }
1121
1122 r_as_graph->custom_data = face_island_index_map;
1123
1124 for (i = island_einnercut_map->count; i--;) {
1126 island_index,
1127 r_as_graph,
1128 positions,
1129 faces,
1130 corner_verts,
1131 island_einnercut_map->indices[i],
1132 done_edges,
1133 edge_to_face_map,
1134 true,
1135 face_island_index_map,
1136 face_centers,
1137 face_status);
1138 }
1139 }
1140
1141 for (pidx_isld = node_num; pidx_isld--;) {
1142 const int pidx = islands ? island_face_map->indices[pidx_isld] : pidx_isld;
1143
1144 if (face_status[pidx_isld] == POLY_COMPLETE) {
1145 continue;
1146 }
1147
1148 for (const int edge : corner_edges.slice(faces[pidx])) {
1149 if (BLI_BITMAP_TEST(done_edges, edge)) {
1150 continue;
1151 }
1152
1154 island_index,
1155 r_as_graph,
1156 positions,
1157 faces,
1158 corner_verts,
1159 edge,
1160 done_edges,
1161 edge_to_face_map,
1162 false,
1163 face_island_index_map,
1164 face_centers,
1165 face_status);
1166 }
1167 face_status[pidx_isld] = POLY_COMPLETE;
1168 }
1169
1170 MEM_freeN(done_edges);
1171 MEM_freeN(face_status);
1172}
1173
1174#undef POLY_UNSET
1175#undef POLY_CENTER_INIT
1176#undef POLY_COMPLETE
1177
1178/* Our 'f_cost' callback func, to find shortest face-path between two remapped-loops.
1179 * Note we do not want to make innercuts 'walls' here,
1180 * just detect when the shortest path goes by those. */
1182 BLI_AStarSolution *as_solution,
1183 BLI_AStarGNLink *link,
1184 const int node_idx_curr,
1185 const int node_idx_next,
1186 const int node_idx_dst)
1187{
1188 float *co_next, *co_dest;
1189
1190 if (link && (POINTER_AS_INT(link->custom_data) != -1)) {
1191 /* An innercut edge... We tag our solution as potentially crossing innercuts.
1192 * Note it might not be the case in the end (AStar will explore around optimal path), but helps
1193 * trimming off some processing later... */
1194 if (!POINTER_AS_INT(as_solution->custom_data)) {
1195 as_solution->custom_data = POINTER_FROM_INT(true);
1196 }
1197 }
1198
1199 /* Our heuristic part of current f_cost is distance from next node to destination one.
1200 * It is guaranteed to be less than (or equal to)
1201 * actual shortest face-path between next node and destination one. */
1202 co_next = (float *)as_graph->nodes[node_idx_next].custom_data;
1203 co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data;
1204 return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) +
1205 len_v3v3(co_next, co_dest);
1206}
1207
1208#define ASTAR_STEPS_MAX 64
1209
1211 const SpaceTransform *space_transform,
1212 const float max_dist,
1213 const float ray_radius,
1214 const Mesh *mesh_dst,
1215 const float (*vert_positions_dst)[3],
1216 const int numverts_dst,
1217 const int *corner_verts_dst,
1218 const int numloops_dst,
1219 const blender::OffsetIndices<int> faces_dst,
1220 const Mesh *me_src,
1221 MeshRemapIslandsCalc gen_islands_src,
1222 const float islands_precision_src,
1223 MeshPairRemap *r_map)
1224{
1225 using namespace blender;
1226 const float full_weight = 1.0f;
1227 const float max_dist_sq = max_dist * max_dist;
1228
1230 BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f));
1231
1232 BKE_mesh_remap_init(r_map, numloops_dst);
1233
1234 if (mode == MREMAP_MODE_TOPOLOGY) {
1235 /* In topology mapping, we assume meshes are identical, islands included! */
1236 BLI_assert(numloops_dst == me_src->corners_num);
1237 for (int i = 0; i < numloops_dst; i++) {
1238 mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
1239 }
1240 }
1241 else {
1242 BVHTreeFromMesh *treedata = nullptr;
1243 BVHTreeNearest nearest = {0};
1244 BVHTreeRayHit rayhit = {0};
1245 int num_trees = 0;
1246 float hit_dist;
1247 float tmp_co[3], tmp_no[3];
1248
1249 const bool use_from_vert = (mode & MREMAP_USE_VERT);
1250
1251 MeshIslandStore island_store = {0};
1252 bool use_islands = false;
1253
1254 BLI_AStarGraph *as_graphdata = nullptr;
1255 BLI_AStarSolution as_solution = {0};
1256 const int isld_steps_src = (islands_precision_src ?
1257 max_ii(int(ASTAR_STEPS_MAX * islands_precision_src + 0.499f),
1258 1) :
1259 0);
1260
1261 blender::Span<blender::float3> face_normals_src;
1262 blender::Span<blender::float3> loop_normals_src;
1263
1264 blender::Span<blender::float3> face_normals_dst;
1265 blender::Span<blender::float3> loop_normals_dst;
1266
1267 blender::Array<blender::float3> face_cents_src;
1268
1269 GroupedSpan<int> vert_to_loop_map_src;
1270 GroupedSpan<int> vert_to_face_map_src;
1271
1272 Array<int> edge_to_face_src_offsets;
1273 Array<int> edge_to_face_src_indices;
1274 GroupedSpan<int> edge_to_face_map_src;
1275
1276 MeshElemMap *face_to_corner_tri_map_src = nullptr;
1277 int *face_to_corner_tri_map_src_buff = nullptr;
1278
1279 /* Unlike above, those are one-to-one mappings, simpler! */
1280 blender::Span<int> loop_to_face_map_src;
1281
1282 const blender::Span<blender::float3> positions_src = me_src->vert_positions();
1283 const int num_verts_src = me_src->verts_num;
1284 const blender::Span<blender::int2> edges_src = me_src->edges();
1285 const blender::OffsetIndices faces_src = me_src->faces();
1286 const blender::Span<int> corner_verts_src = me_src->corner_verts();
1287 const blender::Span<int> corner_edges_src = me_src->corner_edges();
1288 blender::Span<blender::int3> corner_tris_src;
1289 blender::Span<int> tri_faces_src;
1290
1291 size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE;
1292 float(*vcos_interp)[3] = nullptr;
1293 int *indices_interp = nullptr;
1294 float *weights_interp = nullptr;
1295
1296 int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
1297
1298 IslandResult **islands_res;
1299 size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
1300
1301 if (!use_from_vert) {
1302 vcos_interp = static_cast<float(*)[3]>(
1303 MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__));
1304 indices_interp = static_cast<int *>(
1305 MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__));
1306 weights_interp = static_cast<float *>(
1307 MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__));
1308 }
1309
1310 {
1311 const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL);
1312 const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ);
1313 const bool need_pnors_src = need_lnors_src ||
1314 ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL));
1315 const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
1316
1317 if (need_pnors_dst) {
1318 face_normals_dst = mesh_dst->face_normals();
1319 }
1320 if (need_lnors_dst) {
1321 loop_normals_dst = mesh_dst->corner_normals();
1322 }
1323 if (need_pnors_src) {
1324 face_normals_src = me_src->face_normals();
1325 }
1326 if (need_lnors_src) {
1327 loop_normals_src = me_src->corner_normals();
1328 }
1329 }
1330
1331 if (use_from_vert) {
1332 vert_to_loop_map_src = me_src->vert_to_corner_map();
1333 if (mode & MREMAP_USE_POLY) {
1334 vert_to_face_map_src = me_src->vert_to_face_map();
1335 }
1336 }
1337
1338 /* Needed for islands (or plain mesh) to AStar graph conversion. */
1339 edge_to_face_map_src = bke::mesh::build_edge_to_face_map(faces_src,
1340 corner_edges_src,
1341 int(edges_src.size()),
1342 edge_to_face_src_offsets,
1343 edge_to_face_src_indices);
1344
1345 if (use_from_vert) {
1346 loop_to_face_map_src = me_src->corner_to_face_map();
1347 face_cents_src.reinitialize(faces_src.size());
1348 for (const int64_t i : faces_src.index_range()) {
1349 face_cents_src[i] = blender::bke::mesh::face_center_calc(
1350 positions_src, corner_verts_src.slice(faces_src[i]));
1351 }
1352 }
1353
1354 /* Island makes things slightly more complex here.
1355 * Basically, we:
1356 * * Make one treedata for each island's elements.
1357 * * Check all loops of a same dest face against all treedata.
1358 * * Choose the island's elements giving the best results.
1359 */
1360
1361 /* First, generate the islands, if possible. */
1362 if (gen_islands_src) {
1363 const bool *uv_seams = static_cast<const bool *>(
1364 CustomData_get_layer_named(&me_src->edge_data, CD_PROP_BOOL, ".uv_seam"));
1365 use_islands = gen_islands_src(reinterpret_cast<const float(*)[3]>(positions_src.data()),
1366 num_verts_src,
1367 edges_src.data(),
1368 int(edges_src.size()),
1369 uv_seams,
1370 faces_src,
1371 corner_verts_src.data(),
1372 corner_edges_src.data(),
1373 int(corner_verts_src.size()),
1374 &island_store);
1375
1376 num_trees = use_islands ? island_store.islands_num : 1;
1377 treedata = static_cast<BVHTreeFromMesh *>(
1378 MEM_callocN(sizeof(*treedata) * size_t(num_trees), __func__));
1379 if (isld_steps_src) {
1380 as_graphdata = static_cast<BLI_AStarGraph *>(
1381 MEM_callocN(sizeof(*as_graphdata) * size_t(num_trees), __func__));
1382 }
1383
1384 if (use_islands) {
1385 /* We expect our islands to contain face indices, with edge indices of 'inner cuts',
1386 * and a mapping loops -> islands indices.
1387 * This implies all loops of a same face are in the same island. */
1388 BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) &&
1389 (island_store.island_type == MISLAND_TYPE_POLY) &&
1390 (island_store.innercut_type == MISLAND_TYPE_EDGE));
1391 }
1392 }
1393 else {
1394 num_trees = 1;
1395 treedata = static_cast<BVHTreeFromMesh *>(MEM_callocN(sizeof(*treedata), __func__));
1396 if (isld_steps_src) {
1397 as_graphdata = static_cast<BLI_AStarGraph *>(MEM_callocN(sizeof(*as_graphdata), __func__));
1398 }
1399 }
1400
1401 /* Build our AStar graphs. */
1402 if (isld_steps_src) {
1403 for (tindex = 0; tindex < num_trees; tindex++) {
1404 mesh_island_to_astar_graph(use_islands ? &island_store : nullptr,
1405 tindex,
1406 positions_src,
1407 edge_to_face_map_src,
1408 int(edges_src.size()),
1409 faces_src,
1410 corner_verts_src,
1411 corner_edges_src,
1412 &as_graphdata[tindex]);
1413 }
1414 }
1415
1416 /* Build our BVHtrees, either from verts or tessfaces. */
1417 if (use_from_vert) {
1418 if (use_islands) {
1419 blender::BitVector<> verts_active(num_verts_src);
1420
1421 for (tindex = 0; tindex < num_trees; tindex++) {
1422 MeshElemMap *isld = island_store.islands[tindex];
1423 int num_verts_active = 0;
1424 verts_active.fill(false);
1425 for (int i = 0; i < isld->count; i++) {
1426 for (const int vidx_src : corner_verts_src.slice(faces_src[isld->indices[i]])) {
1427 if (!verts_active[vidx_src]) {
1428 verts_active[vidx_src].set();
1429 num_verts_active++;
1430 }
1431 }
1432 }
1434 &treedata[tindex], positions_src, verts_active, num_verts_active, 0.0, 2, 6);
1435 }
1436 }
1437 else {
1438 BLI_assert(num_trees == 1);
1439 BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
1440 }
1441 }
1442 else { /* We use faces. */
1443 if (use_islands) {
1444 corner_tris_src = me_src->corner_tris();
1445 tri_faces_src = me_src->corner_tri_faces();
1446 blender::BitVector<> corner_tris_active(corner_tris_src.size());
1447
1448 for (tindex = 0; tindex < num_trees; tindex++) {
1449 int corner_tris_num_active = 0;
1450 corner_tris_active.fill(false);
1451 for (const int64_t i : corner_tris_src.index_range()) {
1452 const blender::IndexRange face = faces_src[tri_faces_src[i]];
1453 if (island_store.items_to_islands[face.start()] == tindex) {
1454 corner_tris_active[i].set();
1455 corner_tris_num_active++;
1456 }
1457 }
1458 bvhtree_from_mesh_corner_tris_ex(&treedata[tindex],
1459 positions_src,
1460 corner_verts_src,
1461 corner_tris_src,
1462 corner_tris_active,
1463 corner_tris_num_active,
1464 0.0,
1465 2,
1466 6);
1467 }
1468 }
1469 else {
1470 BLI_assert(num_trees == 1);
1471 BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_CORNER_TRIS, 2);
1472 }
1473 }
1474
1475 /* And check each dest face! */
1476 islands_res = static_cast<IslandResult **>(
1477 MEM_mallocN(sizeof(*islands_res) * size_t(num_trees), __func__));
1478 for (tindex = 0; tindex < num_trees; tindex++) {
1479 islands_res[tindex] = static_cast<IslandResult *>(
1480 MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__));
1481 }
1482 const blender::Span<int> tri_faces = me_src->corner_tri_faces();
1483
1484 for (pidx_dst = 0; pidx_dst < faces_dst.size(); pidx_dst++) {
1485 const blender::IndexRange face_dst = faces_dst[pidx_dst];
1486 float pnor_dst[3];
1487
1488 /* Only in use_from_vert case, we may need faces' centers as fallback
1489 * in case we cannot decide which corner to use from normals only. */
1490 blender::float3 pcent_dst;
1491 bool pcent_dst_valid = false;
1492
1494 copy_v3_v3(pnor_dst, face_normals_dst[pidx_dst]);
1495 if (space_transform) {
1496 BLI_space_transform_apply_normal(space_transform, pnor_dst);
1497 }
1498 }
1499
1500 if (size_t(face_dst.size()) > islands_res_buff_size) {
1501 islands_res_buff_size = size_t(face_dst.size()) + MREMAP_DEFAULT_BUFSIZE;
1502 for (tindex = 0; tindex < num_trees; tindex++) {
1503 islands_res[tindex] = static_cast<IslandResult *>(
1504 MEM_reallocN(islands_res[tindex], sizeof(**islands_res) * islands_res_buff_size));
1505 }
1506 }
1507
1508 for (tindex = 0; tindex < num_trees; tindex++) {
1509 BVHTreeFromMesh *tdata = &treedata[tindex];
1510
1511 for (plidx_dst = 0; plidx_dst < face_dst.size(); plidx_dst++) {
1512 const int vert_dst = corner_verts_dst[face_dst.start() + plidx_dst];
1513 if (use_from_vert) {
1514 blender::Span<int> vert_to_refelem_map_src;
1515
1516 copy_v3_v3(tmp_co, vert_positions_dst[vert_dst]);
1517 nearest.index = -1;
1518
1519 /* Convert the vertex to tree coordinates, if needed. */
1520 if (space_transform) {
1521 BLI_space_transform_apply(space_transform, tmp_co);
1522 }
1523
1524 if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist))
1525 {
1526 float(*nor_dst)[3];
1528 float best_nor_dot = -2.0f;
1529 float best_sqdist_fallback = FLT_MAX;
1530 int best_index_src = -1;
1531
1533 copy_v3_v3(tmp_no, loop_normals_dst[plidx_dst + face_dst.start()]);
1534 if (space_transform) {
1535 BLI_space_transform_apply_normal(space_transform, tmp_no);
1536 }
1537 nor_dst = &tmp_no;
1538 nors_src = loop_normals_src;
1539 vert_to_refelem_map_src = vert_to_loop_map_src[nearest.index];
1540 }
1541 else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */
1542 nor_dst = &pnor_dst;
1543 nors_src = face_normals_src;
1544 vert_to_refelem_map_src = vert_to_face_map_src[nearest.index];
1545 }
1546
1547 for (const int index_src : vert_to_refelem_map_src) {
1548 BLI_assert(index_src != -1);
1549 const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
1550
1551 pidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
1552 loop_to_face_map_src[index_src] :
1553 index_src);
1554 /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
1555 * to check we stay on current island (all loops from a given face are
1556 * on same island!). */
1557 lidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
1558 index_src :
1559 int(faces_src[pidx_src].start()));
1560
1561 /* A same vert may be at the boundary of several islands! Hence, we have to ensure
1562 * face/loop we are currently considering *belongs* to current island! */
1563 if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
1564 continue;
1565 }
1566
1567 if (dot > best_nor_dot - 1e-6f) {
1568 /* We need something as fallback decision in case dest normal matches several
1569 * source normals (see #44522), using distance between faces' centers here. */
1570 float *pcent_src;
1571 float sqdist;
1572
1573 if (!pcent_dst_valid) {
1575 {reinterpret_cast<const blender::float3 *>(vert_positions_dst),
1576 numverts_dst},
1577 blender::Span(corner_verts_dst, numloops_dst).slice(face_dst));
1578 pcent_dst_valid = true;
1579 }
1580 pcent_src = face_cents_src[pidx_src];
1581 sqdist = len_squared_v3v3(pcent_dst, pcent_src);
1582
1583 if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
1584 best_nor_dot = dot;
1585 best_sqdist_fallback = sqdist;
1586 best_index_src = index_src;
1587 }
1588 }
1589 }
1590 if (best_index_src == -1) {
1591 /* We found no item to map back from closest vertex... */
1592 best_nor_dot = -1.0f;
1593 hit_dist = FLT_MAX;
1594 }
1595 else if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
1596 /* Our best_index_src is a face one for now!
1597 * Have to find its loop matching our closest vertex. */
1598 const blender::IndexRange face_src = faces_src[best_index_src];
1599 for (plidx_src = 0; plidx_src < face_src.size(); plidx_src++) {
1600 const int vert_src = corner_verts_src[face_src.start() + plidx_src];
1601 if (vert_src == nearest.index) {
1602 best_index_src = plidx_src + int(face_src.start());
1603 break;
1604 }
1605 }
1606 }
1607 best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
1608 islands_res[tindex][plidx_dst].factor = hit_dist ? (best_nor_dot / hit_dist) : 1e18f;
1609 islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1610 islands_res[tindex][plidx_dst].index_src = best_index_src;
1611 }
1612 else {
1613 /* No source for this dest loop! */
1614 islands_res[tindex][plidx_dst].factor = 0.0f;
1615 islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
1616 islands_res[tindex][plidx_dst].index_src = -1;
1617 }
1618 }
1619 else if (mode & MREMAP_USE_NORPROJ) {
1620 int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
1621 float w = 1.0f;
1622
1623 copy_v3_v3(tmp_co, vert_positions_dst[vert_dst]);
1624 copy_v3_v3(tmp_no, loop_normals_dst[plidx_dst + face_dst.start()]);
1625
1626 /* We do our transform here, since we may do several raycast/nearest queries. */
1627 if (space_transform) {
1628 BLI_space_transform_apply(space_transform, tmp_co);
1629 BLI_space_transform_apply_normal(space_transform, tmp_no);
1630 }
1631
1632 while (n--) {
1634 tdata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
1635 {
1636 islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w;
1637 islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1638 islands_res[tindex][plidx_dst].index_src = tri_faces[rayhit.index];
1639 copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co);
1640 break;
1641 }
1642 /* Next iteration will get bigger radius but smaller weight! */
1644 }
1645 if (n == -1) {
1646 /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to
1647 * have only part of one dest face's loops to map to source.
1648 * Note that since we give this a null weight, if whole weight for a given face
1649 * is null, it means none of its loop mapped to this source island,
1650 * hence we can skip it later.
1651 */
1652 copy_v3_v3(tmp_co, vert_positions_dst[vert_dst]);
1653 nearest.index = -1;
1654
1655 /* Convert the vertex to tree coordinates, if needed. */
1656 if (space_transform) {
1657 BLI_space_transform_apply(space_transform, tmp_co);
1658 }
1659
1660 /* In any case, this fallback nearest hit should have no weight at all
1661 * in 'best island' decision! */
1662 islands_res[tindex][plidx_dst].factor = 0.0f;
1663
1665 tdata, &nearest, tmp_co, max_dist_sq, &hit_dist))
1666 {
1667 islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1668 islands_res[tindex][plidx_dst].index_src = tri_faces[nearest.index];
1669 copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
1670 }
1671 else {
1672 /* No source for this dest loop! */
1673 islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
1674 islands_res[tindex][plidx_dst].index_src = -1;
1675 }
1676 }
1677 }
1678 else { /* Nearest face either to use all its loops/verts or just closest one. */
1679 copy_v3_v3(tmp_co, vert_positions_dst[vert_dst]);
1680 nearest.index = -1;
1681
1682 /* Convert the vertex to tree coordinates, if needed. */
1683 if (space_transform) {
1684 BLI_space_transform_apply(space_transform, tmp_co);
1685 }
1686
1687 if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist))
1688 {
1689 islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f;
1690 islands_res[tindex][plidx_dst].hit_dist = hit_dist;
1691 islands_res[tindex][plidx_dst].index_src = tri_faces[nearest.index];
1692 copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
1693 }
1694 else {
1695 /* No source for this dest loop! */
1696 islands_res[tindex][plidx_dst].factor = 0.0f;
1697 islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
1698 islands_res[tindex][plidx_dst].index_src = -1;
1699 }
1700 }
1701 }
1702 }
1703
1704 /* And now, find best island to use! */
1705 /* We have to first select the 'best source island' for given dst face and its loops.
1706 * Then, we have to check that face does not 'spread' across some island's limits
1707 * (like inner seams for UVs, etc.).
1708 * Note we only still partially support that kind of situation here, i.e.
1709 * Faces spreading over actual cracks
1710 * (like a narrow space without faces on src, splitting a 'tube-like' geometry).
1711 * That kind of situation should be relatively rare, though.
1712 */
1713 /* XXX This block in itself is big and complex enough to be a separate function but...
1714 * it uses a bunch of locale vars.
1715 * Not worth sending all that through parameters (for now at least). */
1716 {
1717 BLI_AStarGraph *as_graph = nullptr;
1718 int *face_island_index_map = nullptr;
1719 int pidx_src_prev = -1;
1720
1721 MeshElemMap *best_island = nullptr;
1722 float best_island_fac = 0.0f;
1723 int best_island_index = -1;
1724
1725 for (tindex = 0; tindex < num_trees; tindex++) {
1726 float island_fac = 0.0f;
1727
1728 for (plidx_dst = 0; plidx_dst < face_dst.size(); plidx_dst++) {
1729 island_fac += islands_res[tindex][plidx_dst].factor;
1730 }
1731 island_fac /= float(face_dst.size());
1732
1733 if (island_fac > best_island_fac) {
1734 best_island_fac = island_fac;
1735 best_island_index = tindex;
1736 }
1737 }
1738
1739 if (best_island_index != -1 && isld_steps_src) {
1740 best_island = use_islands ? island_store.islands[best_island_index] : nullptr;
1741 as_graph = &as_graphdata[best_island_index];
1742 face_island_index_map = (int *)as_graph->custom_data;
1743 BLI_astar_solution_init(as_graph, &as_solution, nullptr);
1744 }
1745
1746 for (plidx_dst = 0; plidx_dst < face_dst.size(); plidx_dst++) {
1747 IslandResult *isld_res;
1748 lidx_dst = plidx_dst + int(face_dst.start());
1749
1750 if (best_island_index == -1) {
1751 /* No source for any loops of our dest face in any source islands. */
1752 BKE_mesh_remap_item_define_invalid(r_map, lidx_dst);
1753 continue;
1754 }
1755
1756 as_solution.custom_data = POINTER_FROM_INT(false);
1757
1758 isld_res = &islands_res[best_island_index][plidx_dst];
1759 if (use_from_vert) {
1760 /* Indices stored in islands_res are those of loops, one per dest loop. */
1761 lidx_src = isld_res->index_src;
1762 if (lidx_src >= 0) {
1763 pidx_src = loop_to_face_map_src[lidx_src];
1764 /* If prev and curr face are the same, no need to do anything more!!! */
1765 if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
1766 int pidx_isld_src, pidx_isld_src_prev;
1767 if (face_island_index_map) {
1768 pidx_isld_src = face_island_index_map[pidx_src];
1769 pidx_isld_src_prev = face_island_index_map[pidx_src_prev];
1770 }
1771 else {
1772 pidx_isld_src = pidx_src;
1773 pidx_isld_src_prev = pidx_src_prev;
1774 }
1775
1776 BLI_astar_graph_solve(as_graph,
1777 pidx_isld_src_prev,
1778 pidx_isld_src,
1780 &as_solution,
1781 isld_steps_src);
1782 if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
1783 /* Find first 'cutting edge' on path, and bring back lidx_src on face just
1784 * before that edge.
1785 * Note we could try to be much smarter, g.g. Storing a whole face's indices,
1786 * and making decision (on which side of cutting edge(s!) to be) on the end,
1787 * but this is one more level of complexity, better to first see if
1788 * simple solution works!
1789 */
1790 int last_valid_pidx_isld_src = -1;
1791 /* Note we go backward here, from dest to src face. */
1792 for (int i = as_solution.steps - 1; i--;) {
1793 BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
1794 const int eidx = POINTER_AS_INT(as_link->custom_data);
1795 pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
1796 BLI_assert(pidx_isld_src != -1);
1797 if (eidx != -1) {
1798 /* we are 'crossing' a cutting edge. */
1799 last_valid_pidx_isld_src = pidx_isld_src;
1800 }
1801 }
1802 if (last_valid_pidx_isld_src != -1) {
1803 /* Find a new valid loop in that new face (nearest one for now).
1804 * Note we could be much more subtle here, again that's for later... */
1805 float best_dist_sq = FLT_MAX;
1806
1807 copy_v3_v3(tmp_co, vert_positions_dst[corner_verts_dst[lidx_dst]]);
1808
1809 /* We do our transform here,
1810 * since we may do several raycast/nearest queries. */
1811 if (space_transform) {
1812 BLI_space_transform_apply(space_transform, tmp_co);
1813 }
1814
1815 pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] :
1816 last_valid_pidx_isld_src);
1817 const blender::IndexRange face_src = faces_src[pidx_src];
1818 for (const int64_t corner : face_src) {
1819 const int vert_src = corner_verts_src[corner];
1820 const float dist_sq = len_squared_v3v3(positions_src[vert_src], tmp_co);
1821 if (dist_sq < best_dist_sq) {
1822 best_dist_sq = dist_sq;
1823 lidx_src = int(corner);
1824 }
1825 }
1826 }
1827 }
1828 }
1830 lidx_dst,
1831 isld_res->hit_dist,
1832 best_island_index,
1833 1,
1834 &lidx_src,
1835 &full_weight);
1836 pidx_src_prev = pidx_src;
1837 }
1838 else {
1839 /* No source for this loop in this island. */
1840 /* TODO: would probably be better to get a source
1841 * at all cost in best island anyway? */
1843 r_map, lidx_dst, FLT_MAX, best_island_index, 0, nullptr, nullptr);
1844 }
1845 }
1846 else {
1847 /* Else, we use source face, indices stored in islands_res are those of faces. */
1848 pidx_src = isld_res->index_src;
1849 if (pidx_src >= 0) {
1850 float *hit_co = isld_res->hit_point;
1851 int best_loop_index_src;
1852
1853 const blender::IndexRange face_src = faces_src[pidx_src];
1854 /* If prev and curr face are the same, no need to do anything more!!! */
1855 if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
1856 int pidx_isld_src, pidx_isld_src_prev;
1857 if (face_island_index_map) {
1858 pidx_isld_src = face_island_index_map[pidx_src];
1859 pidx_isld_src_prev = face_island_index_map[pidx_src_prev];
1860 }
1861 else {
1862 pidx_isld_src = pidx_src;
1863 pidx_isld_src_prev = pidx_src_prev;
1864 }
1865
1866 BLI_astar_graph_solve(as_graph,
1867 pidx_isld_src_prev,
1868 pidx_isld_src,
1870 &as_solution,
1871 isld_steps_src);
1872 if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
1873 /* Find first 'cutting edge' on path, and bring back lidx_src on face just
1874 * before that edge.
1875 * Note we could try to be much smarter: e.g. Storing a whole face's indices,
1876 * and making decision (one which side of cutting edge(s)!) to be on the end,
1877 * but this is one more level of complexity, better to first see if
1878 * simple solution works!
1879 */
1880 int last_valid_pidx_isld_src = -1;
1881 /* Note we go backward here, from dest to src face. */
1882 for (int i = as_solution.steps - 1; i--;) {
1883 BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
1884 int eidx = POINTER_AS_INT(as_link->custom_data);
1885
1886 pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
1887 BLI_assert(pidx_isld_src != -1);
1888 if (eidx != -1) {
1889 /* we are 'crossing' a cutting edge. */
1890 last_valid_pidx_isld_src = pidx_isld_src;
1891 }
1892 }
1893 if (last_valid_pidx_isld_src != -1) {
1894 /* Find a new valid loop in that new face (nearest point on face for now).
1895 * Note we could be much more subtle here, again that's for later... */
1896 float best_dist_sq = FLT_MAX;
1897 int j;
1898
1899 const int vert_dst = corner_verts_dst[lidx_dst];
1900 copy_v3_v3(tmp_co, vert_positions_dst[vert_dst]);
1901
1902 /* We do our transform here,
1903 * since we may do several raycast/nearest queries. */
1904 if (space_transform) {
1905 BLI_space_transform_apply(space_transform, tmp_co);
1906 }
1907
1908 pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] :
1909 last_valid_pidx_isld_src);
1910
1911 /* Create that one on demand. */
1912 if (face_to_corner_tri_map_src == nullptr) {
1913 BKE_mesh_origindex_map_create_corner_tri(&face_to_corner_tri_map_src,
1914 &face_to_corner_tri_map_src_buff,
1915 faces_src,
1916 tri_faces_src.data(),
1917 int(tri_faces_src.size()));
1918 }
1919
1920 for (j = face_to_corner_tri_map_src[pidx_src].count; j--;) {
1921 float h[3];
1922 const blender::int3 &tri =
1923 corner_tris_src[face_to_corner_tri_map_src[pidx_src].indices[j]];
1924 float dist_sq;
1925
1927 tmp_co,
1928 positions_src[corner_verts_src[tri[0]]],
1929 positions_src[corner_verts_src[tri[1]]],
1930 positions_src[corner_verts_src[tri[2]]]);
1931 dist_sq = len_squared_v3v3(tmp_co, h);
1932 if (dist_sq < best_dist_sq) {
1933 copy_v3_v3(hit_co, h);
1934 best_dist_sq = dist_sq;
1935 }
1936 }
1937 }
1938 }
1939 }
1940
1941 if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) {
1943 corner_verts_src,
1944 positions_src,
1945 hit_co,
1946 &buff_size_interp,
1947 &vcos_interp,
1948 true,
1949 &indices_interp,
1950 &weights_interp,
1951 false,
1952 &best_loop_index_src);
1953
1955 lidx_dst,
1956 isld_res->hit_dist,
1957 best_island_index,
1958 1,
1959 &best_loop_index_src,
1960 &full_weight);
1961 }
1962 else {
1963 const int sources_num = mesh_remap_interp_face_data_get(face_src,
1964 corner_verts_src,
1965 positions_src,
1966 hit_co,
1967 &buff_size_interp,
1968 &vcos_interp,
1969 true,
1970 &indices_interp,
1971 &weights_interp,
1972 true,
1973 nullptr);
1974
1976 lidx_dst,
1977 isld_res->hit_dist,
1978 best_island_index,
1979 sources_num,
1980 indices_interp,
1981 weights_interp);
1982 }
1983
1984 pidx_src_prev = pidx_src;
1985 }
1986 else {
1987 /* No source for this loop in this island. */
1988 /* TODO: would probably be better to get a source
1989 * at all cost in best island anyway? */
1991 r_map, lidx_dst, FLT_MAX, best_island_index, 0, nullptr, nullptr);
1992 }
1993 }
1994 }
1995
1996 BLI_astar_solution_clear(&as_solution);
1997 }
1998 }
1999
2000 for (tindex = 0; tindex < num_trees; tindex++) {
2001 MEM_freeN(islands_res[tindex]);
2002 free_bvhtree_from_mesh(&treedata[tindex]);
2003 if (isld_steps_src) {
2004 BLI_astar_graph_free(&as_graphdata[tindex]);
2005 }
2006 }
2007 MEM_freeN(islands_res);
2008 BKE_mesh_loop_islands_free(&island_store);
2009 MEM_freeN(treedata);
2010 if (isld_steps_src) {
2011 MEM_freeN(as_graphdata);
2012 BLI_astar_solution_free(&as_solution);
2013 }
2014
2015 if (face_to_corner_tri_map_src) {
2016 MEM_freeN(face_to_corner_tri_map_src);
2017 }
2018 if (face_to_corner_tri_map_src_buff) {
2019 MEM_freeN(face_to_corner_tri_map_src_buff);
2020 }
2021 if (vcos_interp) {
2022 MEM_freeN(vcos_interp);
2023 }
2024 if (indices_interp) {
2025 MEM_freeN(indices_interp);
2026 }
2027 if (weights_interp) {
2028 MEM_freeN(weights_interp);
2029 }
2030 }
2031}
2032
2034 const SpaceTransform *space_transform,
2035 const float max_dist,
2036 const float ray_radius,
2037 const Mesh *mesh_dst,
2038 const float (*vert_positions_dst)[3],
2039 const int numverts_dst,
2040 const int *corner_verts_dst,
2041 const blender::OffsetIndices<int> faces_dst,
2042 const Mesh *me_src,
2043 MeshPairRemap *r_map)
2044{
2045 const float full_weight = 1.0f;
2046 const float max_dist_sq = max_dist * max_dist;
2047 blender::Span<blender::float3> face_normals_dst;
2048 blender::float3 tmp_co, tmp_no;
2049
2051
2052 if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
2053 face_normals_dst = mesh_dst->face_normals();
2054 }
2055
2056 BKE_mesh_remap_init(r_map, int(faces_dst.size()));
2057
2058 if (mode == MREMAP_MODE_TOPOLOGY) {
2059 BLI_assert(faces_dst.size() == me_src->faces_num);
2060 for (const int64_t i : faces_dst.index_range()) {
2061 const int index = int(i);
2062 mesh_remap_item_define(r_map, int(i), FLT_MAX, 0, 1, &index, &full_weight);
2063 }
2064 }
2065 else {
2066 BVHTreeFromMesh treedata = {nullptr};
2067 BVHTreeNearest nearest = {0};
2068 BVHTreeRayHit rayhit = {0};
2069 float hit_dist;
2070 const blender::Span<int> tri_faces = me_src->corner_tri_faces();
2071
2073
2074 if (mode == MREMAP_MODE_POLY_NEAREST) {
2075 nearest.index = -1;
2076
2077 for (const int64_t i : faces_dst.index_range()) {
2078 const blender::IndexRange face = faces_dst[i];
2080 {reinterpret_cast<const blender::float3 *>(vert_positions_dst), numverts_dst},
2081 {&corner_verts_dst[face.start()], face.size()});
2082
2083 /* Convert the vertex to tree coordinates, if needed. */
2084 if (space_transform) {
2085 BLI_space_transform_apply(space_transform, tmp_co);
2086 }
2087
2088 if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist))
2089 {
2090 const int face_index = tri_faces[nearest.index];
2091 mesh_remap_item_define(r_map, int(i), hit_dist, 0, 1, &face_index, &full_weight);
2092 }
2093 else {
2094 /* No source for this dest face! */
2096 }
2097 }
2098 }
2099 else if (mode == MREMAP_MODE_POLY_NOR) {
2100 for (const int64_t i : faces_dst.index_range()) {
2101 const blender::IndexRange face = faces_dst[i];
2102
2104 {reinterpret_cast<const blender::float3 *>(vert_positions_dst), numverts_dst},
2105 {&corner_verts_dst[face.start()], face.size()});
2106 copy_v3_v3(tmp_no, face_normals_dst[i]);
2107
2108 /* Convert the vertex to tree coordinates, if needed. */
2109 if (space_transform) {
2110 BLI_space_transform_apply(space_transform, tmp_co);
2111 BLI_space_transform_apply_normal(space_transform, tmp_no);
2112 }
2113
2115 &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist))
2116 {
2117 const int face_index = tri_faces[rayhit.index];
2118 mesh_remap_item_define(r_map, int(i), hit_dist, 0, 1, &face_index, &full_weight);
2119 }
2120 else {
2121 /* No source for this dest face! */
2123 }
2124 }
2125 }
2126 else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) {
2127 /* We cast our rays randomly, with a pseudo-even distribution
2128 * (since we spread across tessellated triangles,
2129 * with additional weighting based on each triangle's relative area). */
2130 RNG *rng = BLI_rng_new(0);
2131
2132 const size_t numfaces_src = size_t(me_src->faces_num);
2133
2134 /* Here it's simpler to just allocate for all faces :/ */
2135 int *indices = static_cast<int *>(MEM_mallocN(sizeof(*indices) * numfaces_src, __func__));
2136 float *weights = static_cast<float *>(
2137 MEM_mallocN(sizeof(*weights) * numfaces_src, __func__));
2138
2139 size_t tmp_face_size = MREMAP_DEFAULT_BUFSIZE;
2140 float(*face_vcos_2d)[2] = static_cast<float(*)[2]>(
2141 MEM_mallocN(sizeof(*face_vcos_2d) * tmp_face_size, __func__));
2142 /* Tessellated 2D face, always (num_loops - 2) triangles. */
2143 int(*tri_vidx_2d)[3] = static_cast<int(*)[3]>(
2144 MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_face_size - 2), __func__));
2145
2146 for (const int64_t i : faces_dst.index_range()) {
2147 /* For each dst face, we sample some rays from it (2D grid in pnor space)
2148 * and use their hits to interpolate from source faces. */
2149 /* NOTE: dst face is early-converted into src space! */
2150 const blender::IndexRange face = faces_dst[i];
2151
2152 int tot_rays, done_rays = 0;
2153 float face_area_2d_inv, done_area = 0.0f;
2154
2155 blender::float3 pcent_dst;
2156 float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3];
2157 float faces_dst_2d_min[2], faces_dst_2d_max[2], faces_dst_2d_z;
2158 float faces_dst_2d_size[2];
2159
2160 float totweights = 0.0f;
2161 float hit_dist_accum = 0.0f;
2162 int sources_num = 0;
2163 const int tris_num = int(face.size()) - 2;
2164 int j;
2165
2167 {reinterpret_cast<const blender::float3 *>(vert_positions_dst), numverts_dst},
2168 {&corner_verts_dst[face.start()], face.size()});
2169
2170 copy_v3_v3(tmp_no, face_normals_dst[i]);
2171
2172 /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */
2173 if (space_transform) {
2174 BLI_space_transform_apply(space_transform, pcent_dst);
2175 BLI_space_transform_apply_normal(space_transform, tmp_no);
2176 }
2177
2178 copy_vn_fl(weights, int(numfaces_src), 0.0f);
2179
2180 if (UNLIKELY(size_t(face.size()) > tmp_face_size)) {
2181 tmp_face_size = size_t(face.size());
2182 face_vcos_2d = static_cast<float(*)[2]>(
2183 MEM_reallocN(face_vcos_2d, sizeof(*face_vcos_2d) * tmp_face_size));
2184 tri_vidx_2d = static_cast<int(*)[3]>(
2185 MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_face_size - 2)));
2186 }
2187
2188 axis_dominant_v3_to_m3(to_pnor_2d_mat, tmp_no);
2189 invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat);
2190
2191 mul_m3_v3(to_pnor_2d_mat, pcent_dst);
2192 faces_dst_2d_z = pcent_dst[2];
2193
2194 /* Get (2D) bounding square of our face. */
2195 INIT_MINMAX2(faces_dst_2d_min, faces_dst_2d_max);
2196
2197 for (j = 0; j < face.size(); j++) {
2198 const int vert = corner_verts_dst[face[j]];
2199 copy_v3_v3(tmp_co, vert_positions_dst[vert]);
2200 if (space_transform) {
2201 BLI_space_transform_apply(space_transform, tmp_co);
2202 }
2203 mul_v2_m3v3(face_vcos_2d[j], to_pnor_2d_mat, tmp_co);
2204 minmax_v2v2_v2(faces_dst_2d_min, faces_dst_2d_max, face_vcos_2d[j]);
2205 }
2206
2207 /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
2208 * with lower/upper bounds. */
2209 sub_v2_v2v2(faces_dst_2d_size, faces_dst_2d_max, faces_dst_2d_min);
2210
2211 if (ray_radius) {
2212 tot_rays = int((max_ff(faces_dst_2d_size[0], faces_dst_2d_size[1]) / ray_radius) + 0.5f);
2214 }
2215 else {
2216 /* If no radius (pure rays), give max number of rays! */
2218 }
2219 tot_rays *= tot_rays;
2220
2221 face_area_2d_inv = area_poly_v2(face_vcos_2d, uint(face.size()));
2222 /* In case we have a null-area degenerated face... */
2223 face_area_2d_inv = 1.0f / max_ff(face_area_2d_inv, 1e-9f);
2224
2225 /* Tessellate our face. */
2226 if (face.size() == 3) {
2227 tri_vidx_2d[0][0] = 0;
2228 tri_vidx_2d[0][1] = 1;
2229 tri_vidx_2d[0][2] = 2;
2230 }
2231 if (face.size() == 4) {
2232 tri_vidx_2d[0][0] = 0;
2233 tri_vidx_2d[0][1] = 1;
2234 tri_vidx_2d[0][2] = 2;
2235 tri_vidx_2d[1][0] = 0;
2236 tri_vidx_2d[1][1] = 2;
2237 tri_vidx_2d[1][2] = 3;
2238 }
2239 else {
2240 BLI_polyfill_calc(face_vcos_2d, uint(face.size()), -1, (uint(*)[3])tri_vidx_2d);
2241 }
2242
2243 for (j = 0; j < tris_num; j++) {
2244 float *v1 = face_vcos_2d[tri_vidx_2d[j][0]];
2245 float *v2 = face_vcos_2d[tri_vidx_2d[j][1]];
2246 float *v3 = face_vcos_2d[tri_vidx_2d[j][2]];
2247 int rays_num;
2248
2249 /* All this allows us to get 'absolute' number of rays for each tri,
2250 * avoiding accumulating errors over iterations, and helping better even distribution. */
2251 done_area += area_tri_v2(v1, v2, v3);
2252 rays_num = max_ii(int(float(tot_rays) * done_area * face_area_2d_inv + 0.5f) - done_rays,
2253 0);
2254 done_rays += rays_num;
2255
2256 while (rays_num--) {
2257 int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
2258 float w = 1.0f;
2259
2260 BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co);
2261
2262 tmp_co[2] = faces_dst_2d_z;
2263 mul_m3_v3(from_pnor_2d_mat, tmp_co);
2264
2265 /* At this point, tmp_co is a point on our face surface, in mesh_src space! */
2266 while (n--) {
2268 &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
2269 {
2270 const int face_index = tri_faces[rayhit.index];
2271 weights[face_index] += w;
2272 totweights += w;
2273 hit_dist_accum += hit_dist;
2274 break;
2275 }
2276 /* Next iteration will get bigger radius but smaller weight! */
2278 }
2279 }
2280 }
2281
2282 if (totweights > 0.0f) {
2283 for (j = 0; j < int(numfaces_src); j++) {
2284 if (!weights[j]) {
2285 continue;
2286 }
2287 /* NOTE: sources_num is always <= j! */
2288 weights[sources_num] = weights[j] / totweights;
2289 indices[sources_num] = j;
2290 sources_num++;
2291 }
2293 r_map, int(i), hit_dist_accum / totweights, 0, sources_num, indices, weights);
2294 }
2295 else {
2296 /* No source for this dest face! */
2298 }
2299 }
2300
2301 MEM_freeN(tri_vidx_2d);
2302 MEM_freeN(face_vcos_2d);
2303 MEM_freeN(indices);
2304 MEM_freeN(weights);
2305 BLI_rng_free(rng);
2306 }
2307 else {
2308 CLOG_WARN(&LOG, "Unsupported mesh-to-mesh face mapping mode (%d)!", mode);
2309 memset(r_map->items, 0, sizeof(*r_map->items) * size_t(faces_dst.size()));
2310 }
2311
2312 free_bvhtree_from_mesh(&treedata);
2313 }
2314}
2315
2316#undef MREMAP_RAYCAST_APPROXIMATE_NR
2317#undef MREMAP_RAYCAST_APPROXIMATE_FAC
2318#undef MREMAP_RAYCAST_TRI_SAMPLES_MIN
2319#undef MREMAP_RAYCAST_TRI_SAMPLES_MAX
2320#undef MREMAP_DEFAULT_BUFSIZE
2321
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 * bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data, blender::Span< blender::float3 > vert_positions, blender::BitSpan verts_mask, int verts_num_active, float epsilon, int tree_type, int axis)
BVHTree * bvhtree_from_mesh_corner_tris_ex(BVHTreeFromMesh *data, blender::Span< blender::float3 > vert_positions, blender::Span< int > corner_verts, blender::Span< blender::int3 > corner_tris, blender::BitSpan corner_tris_mask, int corner_tris_num_active, float epsilon, int tree_type, int axis)
@ BVHTREE_FROM_CORNER_TRIS
@ BVHTREE_FROM_EDGES
@ BVHTREE_FROM_VERTS
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool(*)(const float(*vert_positions)[3], int totvert, const blender::int2 *edges, int totedge, const bool *uv_seams, blender::OffsetIndices< int > faces, const int *corner_verts, const int *corner_edges, int corners_num, MeshIslandStore *r_island_store) MeshRemapIslandsCalc
@ MISLAND_TYPE_POLY
@ MISLAND_TYPE_LOOP
@ MISLAND_TYPE_EDGE
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store)
void BKE_mesh_origindex_map_create_corner_tri(MeshElemMap **r_map, int **r_mem, blender::OffsetIndices< int > faces, const int *corner_tri_faces, int corner_tris_num)
@ MREMAP_MODE_VERT_EDGE_NEAREST
@ MREMAP_MODE_VERT_POLYINTERP_VNORPROJ
@ MREMAP_MODE_VERT_FACE_NEAREST
@ MREMAP_MODE_LOOP
@ MREMAP_MODE_EDGE_POLY_NEAREST
@ MREMAP_MODE_POLY
@ MREMAP_MODE_VERT_EDGEINTERP_NEAREST
@ MREMAP_MODE_VERT_NEAREST
@ MREMAP_MODE_LOOP_NEAREST_POLYNOR
@ MREMAP_MODE_EDGE_VERT_NEAREST
@ MREMAP_USE_NORMAL
@ MREMAP_USE_LOOP
@ MREMAP_MODE_TOPOLOGY
@ MREMAP_MODE_VERT
@ MREMAP_USE_POLY
@ MREMAP_MODE_EDGE
@ MREMAP_MODE_EDGE_NEAREST
@ MREMAP_MODE_POLY_NOR
@ MREMAP_MODE_LOOP_NEAREST_LOOPNOR
@ MREMAP_MODE_LOOP_POLY_NEAREST
@ MREMAP_USE_NORPROJ
@ MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ
@ MREMAP_USE_VERT
@ MREMAP_MODE_POLY_POLYINTERP_PNORPROJ
@ MREMAP_MODE_POLY_NEAREST
@ MREMAP_MODE_VERT_POLYINTERP_NEAREST
#define BLI_assert(a)
Definition BLI_assert.h:50
An implementation of the A* (AStar) algorithm to solve shortest path problem.
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph, int node_index_src, int node_index_dst, astar_f_cost f_cost_cb, BLI_AStarSolution *r_solution, int max_steps)
Definition astar.c:145
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
Definition astar.c:96
void BLI_astar_node_init(BLI_AStarGraph *as_graph, int node_index, void *custom_data)
Definition astar.c:41
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph, int node1_index, int node2_index, float cost, void *custom_data)
Definition astar.c:46
void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, void *custom_data)
Definition astar.c:72
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, int node_num, void *custom_data)
Definition astar.c:121
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
Definition astar.c:113
void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
Definition astar.c:137
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:65
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
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)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE float sqrtf_signed(float f)
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float r_i1[3], float r_i2[3])
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
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])
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
float area_poly_v2(const float verts[][2], unsigned int nr)
Definition math_geom.cc:180
void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3])
void mul_m3_v3(const float M[3][3], float r[3])
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 unit_m3(float m[3][3])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void unit_m4(float m[4][4])
Definition rct.c:1127
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3], float r_eigen_vectors[3][3])
Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
void BLI_covariance_m3_v3n(const float(*cos_v3)[3], int cos_v3_num, bool use_sample_correction, float r_covmat[3][3], float r_center[3])
Compute the covariance matrix of given set of 3D coordinates.
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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])
void copy_vn_fl(float *array_tar, int size, float val)
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t)
Definition math_vector.c:99
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
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)
Definition math_vector.c:36
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
Random number functions.
struct RNG * BLI_rng_new(unsigned int seed)
Definition rand.cc:39
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:58
void void void BLI_rng_get_tri_sample_float_v2(struct RNG *rng, const float v1[2], const float v2[2], const float v3[2], float r_pt[2]) ATTR_NONNULL()
Definition rand.cc:108
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define INIT_MINMAX2(min, max)
#define POINTER_FROM_INT(i)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
constexpr int64_t size() const
constexpr int64_t start() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void fill(const bool value)
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define printf
#define sqrtf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float3 cos(float3 v)
#define POLY_UNSET
#define MREMAP_RAYCAST_TRI_SAMPLES_MIN
#define MREMAP_RAYCAST_TRI_SAMPLES_MAX
static void mesh_calc_eigen_matrix(const float(*positions)[3], const float(*vcos)[3], const int numverts, float r_mat[4][4])
void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, const Mesh *mesh_dst, const float(*vert_positions_dst)[3], const int numverts_dst, const int *corner_verts_dst, const int numloops_dst, const blender::OffsetIndices< int > faces_dst, const Mesh *me_src, MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
void BKE_mesh_remap_free(MeshPairRemap *map)
#define MREMAP_RAYCAST_APPROXIMATE_NR
void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index)
static void mesh_island_to_astar_graph(MeshIslandStore *islands, const int island_index, const blender::Span< blender::float3 > positions, const blender::GroupedSpan< int > edge_to_face_map, const int numedges, const blender::OffsetIndices< int > faces, const blender::Span< int > corner_verts, const blender::Span< int > corner_edges, BLI_AStarGraph *r_as_graph)
#define MREMAP_RAYCAST_APPROXIMATE_FAC
void BKE_mesh_remap_find_best_match_from_mesh(const float(*vert_positions_dst)[3], const int numverts_dst, const Mesh *me_src, SpaceTransform *r_space_transform)
static int mesh_remap_interp_face_data_get(const blender::IndexRange face, const blender::Span< int > corner_verts, const blender::Span< blender::float3 > positions_src, const float point[3], size_t *buff_size, float(**vcos)[3], const bool use_loops, int **indices, float **weights, const bool do_weights, int *r_closest_index)
#define POLY_COMPLETE
static float mesh_remap_calc_loops_astar_f_cost(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, const int node_idx_curr, const int node_idx_next, const int node_idx_dst)
static CLG_LogRef LOG
Definition mesh_remap.cc:39
#define MREMAP_DEFAULT_BUFSIZE
static void mesh_remap_item_define(MeshPairRemap *map, const int index, const float, const int island, const int sources_num, const int *indices_src, const float *weights_src)
static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, const int island_index, BLI_AStarGraph *as_graph, const blender::Span< blender::float3 > positions, const blender::OffsetIndices< int > faces, const blender::Span< int > corner_verts, const int edge_idx, BLI_bitmap *done_edges, const blender::GroupedSpan< int > edge_to_face_map, const bool is_edge_innercut, const int *face_island_index_map, float(*face_centers)[3], uchar *face_status)
static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata, BVHTreeNearest *nearest, const float co[3], const float max_dist_sq, float *r_hit_dist)
Definition mesh_remap.cc:45
static bool mesh_remap_bvhtree_query_raycast(BVHTreeFromMesh *treedata, BVHTreeRayHit *rayhit, const float co[3], const float no[3], const float radius, const float max_dist, float *r_hit_dist)
Definition mesh_remap.cc:74
#define ASTAR_STEPS_MAX
#define POLY_CENTER_INIT
void BKE_mesh_remap_calc_edges_from_mesh(const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, const float(*vert_positions_dst)[3], const int numverts_dst, const blender::int2 *edges_dst, const int numedges_dst, const Mesh *me_src, Mesh *me_dst, MeshPairRemap *r_map)
void BKE_mesh_remap_calc_faces_from_mesh(const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, const Mesh *mesh_dst, const float(*vert_positions_dst)[3], const int numverts_dst, const int *corner_verts_dst, const blender::OffsetIndices< int > faces_dst, const Mesh *me_src, MeshPairRemap *r_map)
void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform, const float(*vert_positions_dst)[3], const int numverts_dst, const Mesh *me_src)
void BKE_mesh_remap_calc_verts_from_mesh(const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, const float(*vert_positions_dst)[3], const int numverts_dst, const Mesh *me_src, Mesh *me_dst, MeshPairRemap *r_map)
int edge_other_vert(const int2 edge, const int vert)
Definition BKE_mesh.hh:307
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
void * custom_data
Definition BLI_astar.h:34
BLI_AStarGNode * nodes
Definition BLI_astar.h:59
void * custom_data
Definition BLI_astar.h:61
struct MemArena * mem
Definition BLI_astar.h:63
BLI_AStarGNLink ** prev_links
Definition BLI_astar.h:45
BVHTree_RayCastCallback raycast_callback
BVHTree_NearestPointCallback nearest_callback
float co[3]
Definition BLI_kdopbvh.h:69
float hit_point[3]
MeshElemMap ** islands
MeshPairRemapItem * items
int corners_num
CustomData edge_data
int edges_num
int faces_num
int verts_num
Definition rand.cc:33