diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_remap.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh_remap.c | 97 |
1 files changed, 74 insertions, 23 deletions
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index aca72614094..0ed10687fae 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -707,7 +707,7 @@ void BKE_mesh_remap_calc_edges_from_dm( BLI_space_transform_apply_normal(space_transform, v2_no); } - fill_vn_fl(weights, (int)numedges_src, 0.0f); + copy_vn_fl(weights, (int)numedges_src, 0.0f); /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast), * with lower/upper bounds. */ @@ -977,6 +977,8 @@ void BKE_mesh_remap_calc_loops_from_dm( float (*poly_nors_dst)[3] = NULL; float (*loop_nors_dst)[3] = NULL; + float (*poly_cents_src)[3] = NULL; + MeshElemMap *vert_to_loop_map_src = NULL; int *vert_to_loop_map_src_buff = NULL; MeshElemMap *vert_to_poly_map_src = NULL; @@ -1012,6 +1014,8 @@ void BKE_mesh_remap_calc_loops_from_dm( int *indices_interp = NULL; float *weights_interp = NULL; + MLoop *ml_src, *ml_dst; + MPoly *mp_src, *mp_dst; int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src; IslandResult **islands_res; @@ -1089,11 +1093,13 @@ void BKE_mesh_remap_calc_loops_from_dm( edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src); if (use_from_vert) { loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__); - for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) { - MPoly *mp = &polys_src[pidx_src]; - for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) { + poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__); + for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) { + ml_src = &loops_src[mp_src->loopstart]; + for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) { loop_to_poly_map_src[lidx_src] = pidx_src; } + BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]); } } @@ -1155,10 +1161,13 @@ void BKE_mesh_remap_calc_loops_from_dm( int num_verts_active = 0; BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src); for (i = 0; i < isld->count; i++) { - MPoly *mp_src = &polys_src[isld->indices[i]]; + mp_src = &polys_src[isld->indices[i]]; for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) { - BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); - num_verts_active++; + const unsigned int vidx_src = loops_src[lidx_src].v; + if (!BLI_BITMAP_TEST(verts_active, vidx_src)) { + BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v); + num_verts_active++; + } } } /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ @@ -1199,13 +1208,13 @@ void BKE_mesh_remap_calc_loops_from_dm( int num_faces_active = 0; BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src); for (i = 0; i < num_faces_src; i++) { - MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]]; + mp_src = &polys_src[tessface_to_poly_map_src[i]]; if (island_store.items_to_islands[mp_src->loopstart] == tindex) { BLI_BITMAP_ENABLE(faces_active, i); num_faces_active++; } } - /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ + /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */ bvhtree_from_mesh_faces_ex( &treedata[tindex], verts_src, verts_allocated_src, faces_src, num_faces_src, faces_allocated_src, @@ -1233,10 +1242,14 @@ void BKE_mesh_remap_calc_loops_from_dm( islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__); } - for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) { - MPoly *mp_dst = &polys_dst[pidx_dst]; + for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) { float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst]; + /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which + * corner to use from normals only. */ + float pcent_dst[3]; + bool pcent_dst_valid = false; + if ((size_t)mp_dst->totloop > islands_res_buff_size) { islands_res_buff_size = (size_t)mp_dst->totloop; for (tindex = 0; tindex < num_trees; tindex++) { @@ -1246,8 +1259,8 @@ void BKE_mesh_remap_calc_loops_from_dm( for (tindex = 0; tindex < num_trees; tindex++) { BVHTreeFromMesh *tdata = &treedata[tindex]; - MLoop *ml_dst = &loops_dst[mp_dst->loopstart]; + ml_dst = &loops_dst[mp_dst->loopstart]; for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) { if (use_from_vert) { float tmp_co[3]; @@ -1263,6 +1276,7 @@ void BKE_mesh_remap_calc_loops_from_dm( float (*nor_dst)[3]; float (*nors_src)[3]; float best_nor_dot = -2.0f; + float best_sqdist_fallback = FLT_MAX; int best_index_src = -1; if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { @@ -1279,16 +1293,50 @@ void BKE_mesh_remap_calc_loops_from_dm( for (i = vert_to_refelem_map_src[nearest.index].count; i--;) { const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; const float dot = dot_v3v3(nors_src[index_src], *nor_dst); - if (dot > best_nor_dot) { - best_nor_dot = dot; - best_index_src = index_src; + + pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + loop_to_poly_map_src[index_src] : index_src; + /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it + * to check we stay on current island (all loops from a given poly are + * on same island!). */ + lidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ? + index_src : polys_src[pidx_src].loopstart; + + /* A same vert may be at the boundary of several islands! Hence, we have to ensure + * poly/loop we are currently considering *belongs* to current island! */ + if (use_islands && island_store.items_to_islands[lidx_src] != tindex) { + continue; + } + + if (dot > best_nor_dot - 1e-6f) { + /* We need something as fallback decision in case dest normal matches several + * source normals (see T44522), using distance between polys' centers here. */ + float *pcent_src; + float sqdist; + + mp_src = &polys_src[pidx_src]; + ml_src = &loops_src[mp_src->loopstart]; + + if (!pcent_dst_valid) { + BKE_mesh_calc_poly_center( + mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst); + pcent_dst_valid = true; + } + pcent_src = poly_cents_src[pidx_src]; + sqdist = len_squared_v3v3(pcent_dst, pcent_src); + + if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) { + best_nor_dot = dot; + best_sqdist_fallback = sqdist; + best_index_src = index_src; + } } } if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { /* Our best_index_src is a poly one for now! * Have to find its loop matching our closest vertex. */ - MPoly *mp_src = &polys_src[best_index_src]; - MLoop *ml_src = &loops_src[mp_src->loopstart]; + mp_src = &polys_src[best_index_src]; + ml_src = &loops_src[mp_src->loopstart]; for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) { if ((int)ml_src->v == nearest.index) { best_index_src = plidx_src + mp_src->loopstart; @@ -1296,7 +1344,8 @@ void BKE_mesh_remap_calc_loops_from_dm( } } } - islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f; + best_nor_dot = (best_nor_dot + 1.0f) * 0.5f; + islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist * best_nor_dot) : 1e18f; islands_res[tindex][plidx_dst].hit_dist = hit_dist; islands_res[tindex][plidx_dst].index_src = best_index_src; } @@ -1488,12 +1537,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (last_valid_pidx_isld_src != -1) { /* Find a new valid loop in that new poly (nearest one for now). * Note we could be much more subtle here, again that's for later... */ - MPoly *mp_src; - MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst]; int j; float best_dist_sq = FLT_MAX; float tmp_co[3]; + ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); /* We do our transform here, since we may do several raycast/nearest queries. */ @@ -1532,10 +1580,10 @@ void BKE_mesh_remap_calc_loops_from_dm( /* Else, we use source poly, indices stored in islands_res are those of polygons. */ pidx_src = isld_res->index_src; if (pidx_src >= 0) { - MPoly *mp_src = &polys_src[pidx_src]; float *hit_co = isld_res->hit_point; int best_loop_index_src; + mp_src = &polys_src[pidx_src]; /* If prev and curr poly are the same, no need to do anything more!!! */ if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) { int pidx_isld_src, pidx_isld_src_prev; @@ -1575,11 +1623,11 @@ void BKE_mesh_remap_calc_loops_from_dm( if (last_valid_pidx_isld_src != -1) { /* Find a new valid loop in that new poly (nearest point on poly for now). * Note we could be much more subtle here, again that's for later... */ - MLoop *ml_dst = &loops_dst[lidx_dst]; float best_dist_sq = FLT_MAX; float tmp_co[3]; int j; + ml_dst = &loops_dst[lidx_dst]; copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co); /* We do our transform here, since we may do several raycast/nearest queries. */ @@ -1710,6 +1758,9 @@ void BKE_mesh_remap_calc_loops_from_dm( if (loop_to_poly_map_src) { MEM_freeN(loop_to_poly_map_src); } + if (poly_cents_src) { + MEM_freeN(poly_cents_src); + } if (vcos_interp) { MEM_freeN(vcos_interp); } @@ -1865,7 +1916,7 @@ void BKE_mesh_remap_calc_polys_from_dm( BLI_space_transform_apply_normal(space_transform, tmp_no); } - fill_vn_fl(weights, (int)numpolys_src, 0.0f); + copy_vn_fl(weights, (int)numpolys_src, 0.0f); if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) { tmp_poly_size = (size_t)mp->totloop; |