[Bf-blender-cvs] [9680edf77c5] temp_bmesh_multires: * Implemented bounday/face set corner handling. * New function SCULPT_vertex_is_corner, similar to SCULPT_vertex_is_boundary it takes argument to check face sets. PBVH_FACES/GRIDS version is incomplete. It returns a bitmask of whether the vert is a boundary corner and/or a face set one. * PBVH_BMESH uses a somewhat more expensive calculation to detect corners of face set islands by edge angle. This is currently not done for boundary corners.

Joseph Eagar noreply at git.blender.org
Tue Aug 24 22:23:50 CEST 2021


Commit: 9680edf77c555964322e55fb8d52f033fe8797b6
Author: Joseph Eagar
Date:   Tue Aug 24 13:18:36 2021 -0700
Branches: temp_bmesh_multires
https://developer.blender.org/rB9680edf77c555964322e55fb8d52f033fe8797b6

* Implemented bounday/face set corner handling.
* New function SCULPT_vertex_is_corner, similar to
  SCULPT_vertex_is_boundary it takes argument to
  check face sets.  PBVH_FACES/GRIDS version is
  incomplete.  It returns a bitmask of whether
  the vert is a boundary corner and/or a face
  set one.
* PBVH_BMESH uses a somewhat more expensive
  calculation to detect corners of face set islands by
  edge angle. This is currently not done for boundary
  corners.

Corner pinning now happens in:

* The internal smoother dyntopo uses for stability reasons.
* SCULPT_vertex_neighbor_average_interior.
* Topology rake.
* Dyntopo collapse.

Note that DynTopo always pins face set corners
but everything else only does so if preserve face
sets is on.

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

M	source/blender/blenkernel/intern/dyntopo.c
M	source/blender/blenkernel/intern/pbvh_bmesh.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/editors/sculpt_paint/sculpt_smooth.c
M	source/blender/makesdna/DNA_meshdata_types.h

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

diff --git a/source/blender/blenkernel/intern/dyntopo.c b/source/blender/blenkernel/intern/dyntopo.c
index 023cb324346..22852e2d163 100644
--- a/source/blender/blenkernel/intern/dyntopo.c
+++ b/source/blender/blenkernel/intern/dyntopo.c
@@ -36,6 +36,7 @@
 
 //#define USE_NEW_SPLIT
 #define DYNVERT_ALL_BOUNDARY (DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY)
+#define DYNVERT_ALL_CORNER (DYNVERT_CORNER | DYNVERT_FSET_CORNER)
 
 #define DYNTOPO_MAX_ITER 4096
 
@@ -172,6 +173,10 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v)
   MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
   const bool bound1 = mv1->flag & DYNVERT_ALL_BOUNDARY;
 
+  if (mv1->flag & DYNVERT_ALL_CORNER) {
+    return;
+  }
+
   do {
     BMVert *v2 = e->v1 == v ? e->v2 : e->v1;
 
@@ -1586,16 +1591,15 @@ static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
 
     for (int i = 0; i < totface; i++) {
       if (fs[i] == f2) {
-        fs[i] = NULL;
+        // fs[i] = NULL;
       }
     }
 
-    if (dbl->link == f) {
-      f = NULL;
+    if (dbl->link != f) {
+      // f = NULL;
+      // BM_face_kill(pbvh->bm, dbl->link);
     }
 
-    BM_face_kill(pbvh->bm, dbl->link);
-
     MEM_freeN(dbl);
     dbl = next;
   }
@@ -1910,6 +1914,10 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
       pbvh_check_vert_boundary(pbvh, e->v1);
       pbvh_check_vert_boundary(pbvh, e->v2);
 
+      if ((mv1->flag & DYNVERT_ALL_CORNER) || (mv2->flag & DYNVERT_ALL_CORNER)) {
+        continue;
+      }
+
       if ((mv1->flag & DYNVERT_ALL_BOUNDARY) != (mv2->flag & DYNVERT_ALL_BOUNDARY)) {
         continue;
       }
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index fcd87b81335..e57c6f631d8 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1286,37 +1286,98 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
 
 /***************************** Public API *****************************/
 
+static float sculpt_corner_angle(float *base, float *co1, float *co2)
+{
+  float t1[3], t2[3];
+  sub_v3_v3v3(t1, co1, base);
+  sub_v3_v3v3(t2, co2, base);
+
+  normalize_v3(t1);
+  normalize_v3(t2);
+
+  float th = dot_v3v3(t1, t2);
+
+  return saacos(th);
+}
+
+typedef struct FSetTemp {
+  BMVert *v;
+  int fset;
+  bool boundary;
+} FSetTemp;
+
 void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVert *v)
 {
   MDynTopoVert *mv = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
 
   BMEdge *e = v->e;
   mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY |
-                DYNVERT_NEED_TRIANGULATE);
+                DYNVERT_NEED_TRIANGULATE | DYNVERT_FSET_CORNER | DYNVERT_CORNER |
+                DYNVERT_NEED_VALENCE);
 
   if (!e) {
     mv->flag |= DYNVERT_BOUNDARY;
     return;
   }
 
-  int lastfset = 0;
+  int fset1 = 0;
+  int fset2 = 0;
+  int fset3 = 0;
+  BMVert *vfset1 = NULL;
+  BMVert *vfset2 = NULL;
+  int fset2_count = 0;
+
+  int fset1_count = 0;
+
   bool first = true;
 
+  int val = 0;
+
+  FSetTemp *fsets = NULL;
+  BLI_array_staticdeclare(fsets, 32);
+
   do {
+    BMVert *v2 = v == e->v1 ? e->v2 : e->v1;
+
     if (e->l) {
       int fset = abs(BM_ELEM_CD_GET_INT(e->l->f, cd_faceset_offset));
 
-      if (!first && fset != lastfset) {
-        mv->flag |= DYNVERT_FSET_BOUNDARY;
-      }
-
       if (e->l->f->len > 3) {
         mv->flag |= DYNVERT_NEED_TRIANGULATE;
       }
 
-      lastfset = fset;
+      if (!fset1) {
+        fset1 = fset;
+        vfset1 = v2;
+      }
+      else if (!fset2 && fset != fset1) {
+        fset2 = fset;
+      }
+      else if (!fset3 && fset != fset1 && fset != fset2) {
+        fset3 = fset;
+      }
+
+      if (!vfset2 && fset == fset2 && v2 != vfset1) {
+        vfset2 = v2;
+      }
+
+      if (fset == fset1) {
+        fset1_count++;
+      }
+
+      if (fset == fset2) {
+        fset2_count++;
+      }
+
       first = false;
 
+      bool bound = (e->l == e->l->radial_next) ||
+                   (abs(BM_ELEM_CD_GET_INT(e->l->f, cd_faceset_offset)) !=
+                    abs(BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_faceset_offset)));
+
+      FSetTemp fs = {.fset = fset, .v = v2, .boundary = bound};
+      BLI_array_append(fsets, fs);
+
       // also check e->l->radial_next, in case we are not manifold
       // which can mess up the loop order
       if (e->l->radial_next != e->l) {
@@ -1326,9 +1387,30 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
           mv->flag |= DYNVERT_NEED_TRIANGULATE;
         }
 
-        if (fset != lastfset) {
-          mv->flag |= DYNVERT_FSET_BOUNDARY;
+        if (!fset1) {
+          fset1 = fset;
         }
+        else if (!fset2 && fset != fset1) {
+          fset2 = fset;
+        }
+        else if (!fset3 && fset != fset1 && fset != fset2) {
+          fset3 = fset;
+        }
+
+        if (fset == fset1) {
+          fset1_count++;
+        }
+
+        if (fset == fset2) {
+          fset2_count++;
+        }
+
+        if (!vfset2 && fset == fset2 && v2 != vfset1) {
+          vfset2 = v2;
+        }
+
+        FSetTemp fs = {.fset = fset, .v = v2, .boundary = bound};
+        BLI_array_append(fsets, fs);
       }
     }
 
@@ -1336,8 +1418,63 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
       mv->flag |= DYNVERT_BOUNDARY;
     }
 
+    val++;
     e = e->v1 == v ? e->v1_disk_link.next : e->v2_disk_link.next;
   } while (e != v->e);
+
+  if (fset1 && fset2) {
+    mv->flag |= DYNVERT_FSET_BOUNDARY;
+  }
+
+  if (fset2 && !fset3) {
+    int n = MIN2(fset1_count, fset2_count);
+    float maxth = 0;
+    float maxth2 = 0;
+
+    // find widest angle
+    for (int i = 0; n < 7 && i < BLI_array_len(fsets); i++) {
+      if (!fsets[i].boundary) {
+        continue;
+      }
+
+      for (int j = 0; j < BLI_array_len(fsets); j++) {
+        if (!fsets[j].boundary) {
+          continue;
+        }
+
+        if (i != j && fsets[j].fset == fset1 && fsets[i].v != fsets[j].v) {
+          float th = sculpt_corner_angle(v->co, fsets[i].v->co, fsets[j].v->co);
+          if (th > maxth) {
+            maxth = th;
+          }
+        }
+        if (i != j && fsets[j].fset == fset2 && fsets[i].v != fsets[j].v) {
+          float th = sculpt_corner_angle(v->co, fsets[i].v->co, fsets[j].v->co);
+          if (th > maxth2) {
+            maxth2 = th;
+          }
+        }
+      }
+    }
+
+    bool ok = maxth > 0.25 && maxth < M_PI * 0.55;
+    ok = ok || (maxth2 > 0.25 && maxth2 < M_PI * 0.55);
+
+    // 45 degrees
+    if (ok) {
+      mv->flag |= DYNVERT_FSET_CORNER;
+    }
+  }
+  else if (fset2 && fset3) {
+    mv->flag |= DYNVERT_FSET_CORNER;
+  }
+
+  mv->valence = val;
+  if (val < 4 && (mv->flag & DYNVERT_BOUNDARY)) {
+    mv->flag |= DYNVERT_CORNER;
+  }
+
+  BLI_array_free(fsets);
 }
 
 void BKE_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVert *v)
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 11083dc7617..9013709e9d0 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -33,6 +33,7 @@
 #include "BLI_math_color_blend.h"
 #include "BLI_task.h"
 #include "BLI_utildefines.h"
+#include "atomic_ops.h"
 
 #include "BLT_translation.h"
 
@@ -102,6 +103,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss,
+                                                      const SculptVertRef index);
+
 /* Sculpt PBVH abstraction API
  *
  * This is read-only, for writing use PBVH vertex iterators. There vd.index matches
@@ -1118,6 +1122,47 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
   }
 }
 
+static SculptCornerType sculpt_check_corner_in_base_mesh(const SculptSession *ss,
+                                                         SculptVertRef vertex,
+                                                         bool check_facesets)
+{
+  int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex);
+
+  MeshElemMap *vert_map = &ss->pmap[index];
+  int face_set = -1;
+  int last1 = -1;
+  int last2 = -1;
+
+  int ret = 0;
+
+  if (sculpt_check_boundary_vertex_in_base_mesh(ss, vertex) && ss->pmap[index].count < 4) {
+    ret |= SCULPT_CORNER_BOUNDARY;
+  }
+
+  if (check_facesets) {
+    for (int i = 0; i < ss->pmap[index].count; i++) {
+      if (check_facesets) {
+        if (last2 != last1) {
+          last2 = last1;
+        }
+        if (last1 != face_set) {
+          last1 = face_set;
+        }
+        face_set = abs(ss->face_sets[vert_map->indices[i]]);
+
+        bool corner = last1 != -1 && last2 != -1 && face_set != -1;
+        corner = corner && last1 != last2 && last1 != face_set;
+
+        if (corner) {
+          ret |= SCULPT_CORNER_FACE_SET;
+        }
+      }
+    }
+  }
+
+  return ret;
+}
+
 static bool sculpt_check_unique_face_set_in_base_mesh(const SculptSession *ss,
                                                       SculptVertRef vertex)
 {
@@ -1334,7 +1379,7 @@ static void sculpt_vertex_neighbor_add_nocheck(SculptVertexNeighborIter *iter,
   iter->size++;
 }
 
-static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
+static void sculpt_vertex_neighbors_get_bmesh(const SculptSession *ss,
                                               SculptVertRef index,
                                               SculptVertexNeighborIter *iter)
 {
@@ -1378,7 +1423,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
   } while (e != v->e);
 }
 
-static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
+static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
                                               SculptVertRef vertex,
                                               SculptVertexNeighborIter *iter)
 {
@@ -1418,7 +1463,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
   }
 }
 
-static void sculpt_vertex_neighbors_get_faces_vemap(SculptSession *ss,
+static void sculpt_vertex_neighbors_get_faces_vemap(const Sculp

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list