Fix T44522: loop remapping between meshes when using 'nearest vert, best matching...
authorBastien Montagne <montagne29@wanadoo.fr>
Tue, 28 Apr 2015 13:57:11 +0000 (15:57 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Tue, 28 Apr 2015 14:01:43 +0000 (16:01 +0200)
would fail on coplanar faces (or smooth verts).

Loop remapping is really a tricky topic... For now, we enhance a bit more
our Frankenfunc by using distance between dest and source polygons as
fallback in case we have too much similar normals...

Probably not a perfect solution, but should be robust enough I hope.

One core question remains open though: do we want to stick to 'use only seams
to detect UV islands'? This makes things much simpler, but will obviously fail
in case of actual islands without matching seams. :/

source/blender/blenkernel/intern/mesh_remap.c

index aca72614094f018e7e1698d8e12c9203ddc6b49d..94fe9f993d38f1116a641aa14a197c53d9aa908c 100644 (file)
@@ -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,7 +1161,7 @@ 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++;
@@ -1199,7 +1205,7 @@ 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++;
@@ -1233,10 +1239,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 +1256,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 +1273,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 +1290,38 @@ 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;
+
+                                                               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;
+
+                                                                       pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+                                                                                          loop_to_poly_map_src[index_src] : index_src;
+                                                                       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;
@@ -1488,12 +1521,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 +1564,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 +1607,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 +1742,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);
                }