Commit: 25c5928b2b6a71a426b123a81b605e2fbe5e297e
Author: Bastien Montagne
Date:   Wed Aug 30 16:42:53 2017 +0200
Branches: master
https://developer.blender.org/rB25c5928b2b6a71a426b123a81b605e2fbe5e297e

Refactor 'split faces' mesh code.

Previous version was trying to do a quick and simple process in the case
we were only considering smooth/flat status of faces.

Thing is, even then, the algorithm was not actually working in all
possible situations, e.g. two smooth faces having a single vertex in
common, but no common edges, would not have split that vertex, leading
to incorrect shading etc.

So now, tweaked slightly our split normals code to be able to generate
lnor spaces even when autosmooth is disabled, and we always go that way
when splitting faces.

Using smooth fans from clnor spaces is not only the only way to get 100%
correct results, it also makes face split code simpler.

===================================================================

M       source/blender/blenkernel/intern/mesh.c

===================================================================

diff --git a/source/blender/blenkernel/intern/mesh.c 
b/source/blender/blenkernel/intern/mesh.c
index b89541173e1..2e725cbfbfd 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2059,6 +2059,12 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, 
int type)
                   (me->mselect[me->totselect - 1].type  == type));
 }
 
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr Allows to get computed loop normal space array. 
That data, among other things,
+ *                         contains 'smooth fan' info, useful e.g. to split 
geometry along sharp edges...
+ */
 void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray 
*r_lnors_spacearr)
 {
        float (*r_loopnors)[3];
@@ -2094,7 +2100,10 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, 
MLoopNorSpaceArray *r_lnors_spac
        BKE_mesh_normals_loop_split(
                mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
                mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const 
float (*)[3])polynors, mesh->totpoly,
-               (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, 
r_lnors_spacearr, clnors, NULL);
+               /* Note that we enforce computing clnors when the clnor space 
array is requested by caller here.
+                * However, we obviously only use the autosmooth angle 
threshold only in case autosmooth is enabled. */
+               r_lnors_spacearr != NULL, (mesh->flag & ME_AUTOSMOOTH) != 0 ? 
mesh->smoothresh : (float)M_PI,
+               r_lnors_spacearr, clnors, NULL);
 
        if (free_polynors) {
                MEM_freeN(polynors);
@@ -2126,118 +2135,70 @@ typedef struct SplitFaceNewEdge {
 /* Detect needed new vertices, and update accordingly loops' vertex indices.
  * WARNING! Leaves mesh in invalid state. */
 static int split_faces_prepare_new_verts(
-        const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert 
**new_verts, MemArena *memarena,
-        bool *r_need_vnors_recalc)
+        const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert 
**new_verts, MemArena *memarena)
 {
-       /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and 
we only split out flat polys. */
+       /* This is now mandatory, trying to do the job in simple way without 
that data is doomed to fail, even when only
+        * dealing with smooth/flat faces one can find cases that no simple 
algorithm can handle properly. */
+       BLI_assert(lnors_spacearr != NULL);
+
        const int num_loops = mesh->totloop;
        int num_verts = mesh->totvert;
        MVert *mvert = mesh->mvert;
        MLoop *mloop = mesh->mloop;
 
        BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
+       BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
 
-       if (lnors_spacearr) {
-               BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
-
-               MLoop *ml = mloop;
-               MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
-               for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, 
lnor_space++) {
-                       if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
-                               const int vert_idx = ml->v;
-                               const bool vert_used = 
BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
-                               /* If vert is already used by another smooth 
fan, we need a new vert for this one. */
-                               const int new_vert_idx = vert_used ? 
num_verts++ : vert_idx;
-
-                               BLI_assert(*lnor_space);
-
-                               if ((*lnor_space)->loops) {
-                                       for (LinkNode *lnode = 
(*lnor_space)->loops; lnode; lnode = lnode->next) {
-                                               const int ml_fan_idx = 
GET_INT_FROM_POINTER(lnode->link);
-                                               BLI_BITMAP_ENABLE(done_loops, 
ml_fan_idx);
-                                               if (vert_used) {
-                                                       mloop[ml_fan_idx].v = 
new_vert_idx;
-                                               }
-                                       }
-                               }
-                               else {
-                                       /* Single loop in this fan... */
-                                       BLI_BITMAP_ENABLE(done_loops, loop_idx);
+       MLoop *ml = mloop;
+       MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+
+       for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, 
lnor_space++) {
+               if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
+                       const int vert_idx = ml->v;
+                       const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, 
vert_idx);
+                       /* If vert is already used by another smooth fan, we 
need a new vert for this one. */
+                       const int new_vert_idx = vert_used ? num_verts++ : 
vert_idx;
+
+                       BLI_assert(*lnor_space);
+
+                       if ((*lnor_space)->loops) {
+                               for (LinkNode *lnode = (*lnor_space)->loops; 
lnode; lnode = lnode->next) {
+                                       const int ml_fan_idx = 
GET_INT_FROM_POINTER(lnode->link);
+                                       BLI_BITMAP_ENABLE(done_loops, 
ml_fan_idx);
                                        if (vert_used) {
-                                               ml->v = new_vert_idx;
+                                               mloop[ml_fan_idx].v = 
new_vert_idx;
                                        }
                                }
-
-                               if (!vert_used) {
-                                       BLI_BITMAP_ENABLE(verts_used, vert_idx);
-                                       /* We need to update that vertex's 
normal here, we won't go over it again. */
-                                       /* This is important! *DO NOT* set vnor 
to final computed lnor, vnor should always be defined to
-                                        * 'automatic normal' value computed 
from its polys, not some custom normal.
-                                        * Fortunately, that's the loop normal 
space's 'lnor' reference vector. ;) */
-                                       
normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
-                               }
-                               else {
-                                       /* Add new vert to list. */
-                                       SplitFaceNewVert *new_vert = 
BLI_memarena_alloc(memarena, sizeof(*new_vert));
-                                       new_vert->orig_index = vert_idx;
-                                       new_vert->new_index = new_vert_idx;
-                                       new_vert->vnor = 
(*lnor_space)->vec_lnor;  /* See note above. */
-                                       new_vert->next = *new_verts;
-                                       *new_verts = new_vert;
-                               }
                        }
-               }
-
-               MEM_freeN(done_loops);
-       }
-       else {
-               /* No loop normal spaces available, we only split out flat 
polys. */
-               const int num_polys = mesh->totpoly;
-               const MPoly *mpoly = mesh->mpoly;
-
-               /* We do that in two loops, to keep original edges/verts to 
smooth polys preferencially. */
-               const MPoly *mp = mpoly;
-               for (int i = 0; i < num_polys; i++, mp++) {
-                       if (mp->flag & ME_SMOOTH) {
-                               const MLoop *ml = &mloop[mp->loopstart];
-                               for (int j = 0; j < mp->totloop; j++, ml++) {
-                                       /* Just mark the vertex as 
used/reserved, that way neighbor flat polys, if any,
-                                        * will have to create their own. */
-                                       BLI_BITMAP_ENABLE(verts_used, ml->v);
+                       else {
+                               /* Single loop in this fan... */
+                               BLI_BITMAP_ENABLE(done_loops, loop_idx);
+                               if (vert_used) {
+                                       ml->v = new_vert_idx;
                                }
                        }
-               }
 
-               mp = mpoly;
-               for (int i = 0; i < num_polys; i++, mp++) {
-                       if (!(mp->flag & ME_SMOOTH)) {
-                               MLoop *ml = &mloop[mp->loopstart];
-                               for (int j = 0; j < mp->totloop; j++, ml++) {
-                                       const int vert_idx = ml->v;
-
-                                       if (BLI_BITMAP_TEST(verts_used, 
vert_idx)) {
-                                               /* Add new vert to list. */
-                                               const int new_vert_idx = 
num_verts++;
-                                               ml->v = new_vert_idx;
-
-                                               SplitFaceNewVert *new_vert = 
BLI_memarena_alloc(memarena, sizeof(*new_vert));
-                                               new_vert->orig_index = vert_idx;
-                                               new_vert->new_index = 
new_vert_idx;
-                                               new_vert->vnor = NULL;  /* See 
note below about normals. */
-                                               new_vert->next = *new_verts;
-                                               *new_verts = new_vert;
-                                       }
-                                       else {
-                                               BLI_BITMAP_ENABLE(verts_used, 
vert_idx);
-                                       }
-                               }
-                               /* Note: there is no way to get new normals for 
smooth vertices here (and we don't have direct access
-                                * to poly normals either for flat ones), so 
we'll have to recompute all vnors at the end... */
-                               *r_need_vnors_recalc = true;
+                       if (!vert_used) {
+                               BLI_BITMAP_ENABLE(verts_used, vert_idx);
+                               /* We need to update that vertex's normal here, 
we won't go over it again. */
+                               /* This is important! *DO NOT* set vnor to 
final computed lnor, vnor should always be defined to
+                                * 'automatic normal' value computed from its 
polys, not some custom normal.
+                                * Fortunately, that's the loop normal space's 
'lnor' reference vector. ;) */
+                               normal_float_to_short_v3(mvert[vert_idx].no, 
(*lnor_space)->vec_lnor);
+                       }
+                       else {
+                               /* Add new vert to list. */
+                               SplitFaceNewVert *new_vert = 
BLI_memarena_alloc(memarena, sizeof(*new_vert));
+                               new_vert->orig_index = vert_idx;
+                               new_vert->new_index = new_vert_idx;
+                               new_vert->vnor = (*lnor_space)->vec_lnor;  /* 
See note above. */
+                               new_vert->next = *new_verts;
+                               *new_verts = new_vert;
                        }
                }
        }
 
+       MEM_freeN(done_loops);
        MEM_freeN(verts_used);
 
        return num_verts - mesh->totvert;
@@ -2356,27 +2317,17 @@ void BKE_mesh_split_faces(Mesh *mesh, bool 
free_loop_normals)
        }
        BKE_mesh_tessface_clear(mesh);
 
-       MLoopNorSpaceArray *lnors_spacearr = NULL;
-       MemArena *memarena;
-       bool need_vnors_recalc = false;
-
-       if (mesh->flag & ME_AUTOSMOOTH) {
-               lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__);
-               /* Compute loop normals and loop normal spaces (a.k.a. smooth 
fans of faces around vertices). */
-               BKE_mesh_calc_normals_split_ex(mesh, lnors_spacearr);
-               /* Stealing memarena from loop normals space array. */
-               memarena = lnors_spacearr->mem;
-       }
-       else {
-               /* We still have to split out flat faces... */
-               memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
-       }
+       MLoopNorSpaceArray lnors_spacearr = {NULL};
+       /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of 
faces around vertices). */
+       BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
+       /* Stealing memarena from loop normals space array. */
+       MemArena *memarena = lnors_spacearr.mem;
 
        SplitFaceNewVert *new_verts = NULL;
        SplitFaceNewEdge *new_edges = NULL;
 
        /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new 
vert. */
-       const int num_new_verts = split_faces_prepare_new_verts(mesh, 
lnors_spacearr, &new_verts, memarena, &need_vnors_recalc);
+       const int num_new_verts = split_faces_prepare_new_verts(mesh, 
&lnors_spacearr, &new_verts, memarena);
 
        if (num_new_verts > 0) {
                /* Reminder: beyond this point, there is no way out, mesh is in 
invalid state (due to early-reassignment of
@@ -2388,9 +2339,9 @@ void BKE_mesh_split_faces(Mesh *mesh, bool 
free_loop_normals)
 
                /* Reallocate all vert and edge related data. */
                mesh->totvert += num_new_verts;
-               mesh->totedge += num_new_edges;
                CustomData_realloc(&mesh->vdata, mesh->totvert);
                if (do_edges) {
+                       mesh->totedge += num_new_edges;
                        CustomData_realloc(&mesh->edata, mesh->totedge);
                }
                /* Update pointers to a newly allocated memory. */
@@ -2410,18 +2361,9 @@

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to