[Bf-blender-cvs] [70a49560208] temp_bmesh_multires: Sculpt dyntopo: Removed triangle limit for PBVH_BMESH

Joseph Eagar noreply at git.blender.org
Wed Jul 21 05:00:28 CEST 2021


Commit: 70a49560208b1346c037ad24fb268fb190b87b9d
Author: Joseph Eagar
Date:   Tue Jul 20 19:46:00 2021 -0700
Branches: temp_bmesh_multires
https://developer.blender.org/rB70a49560208b1346c037ad24fb268fb190b87b9d

Sculpt dyntopo: Removed triangle limit for PBVH_BMESH

* PBVH_BMESH now supports faces other then triangles;

* Dyntopo triangulates faces as it finds them.
  - I looked into methods of preserving quads and failed to
    find anything that worked well in practice; it actually
    worked better to use topology rake to align triangles
    into quads and then mark diagonal edges for later dissolving
    then to try to preserve quads explicitly (I've not
    implementated that here, that was research code).
  - To avoid excessive cache-destroying loops over vertex-faces,
    DynTopo flags which verts have non-triangle faces.

* PBVHTriBuf now builds edge buffers so we can avoid drawing
  tesselation phantom edges.

* BMLog also now supports arbitrary faces.  It still does not
  support edges though.

TODO:

* Fix vcol cell shading mode
* Make sure indexed drawing works

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

M	source/blender/blenkernel/BKE_pbvh.h
M	source/blender/blenkernel/intern/dyntopo.c
M	source/blender/blenkernel/intern/pbvh_bmesh.c
M	source/blender/bmesh/intern/bmesh_log.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_dyntopo.c
M	source/blender/gpu/intern/gpu_buffers.c
M	source/blender/makesdna/DNA_meshdata_types.h

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

diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 67c97f17cc0..21f8d9903d8 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -54,7 +54,9 @@ BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
 }
 
 typedef struct PBVHTri {
-  int v[3];  // references into PBVHTriBuf->verts
+  int v[3];       // references into PBVHTriBuf->verts
+  intptr_t l[3];  // loops
+  int eflag;      // bitmask of which edges in the tri are real edges in the mesh
 
   float no[3];
   SculptFaceRef f;
@@ -63,8 +65,9 @@ typedef struct PBVHTri {
 typedef struct PBVHTriBuf {
   PBVHTri *tris;
   SculptVertRef *verts;
-  int tottri, totvert;
-  int tris_size, verts_size;
+  int *edges;
+  int totvert, totedge, tottri;
+  int verts_size, edges_size, tris_size;
 
   // private field
   intptr_t *loops;
@@ -736,6 +739,8 @@ PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i);
 struct BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh);
 void BKE_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, struct BMVert *v);
 
+#define DYNTOPO_DYNAMIC_TESS
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/blenkernel/intern/dyntopo.c b/source/blender/blenkernel/intern/dyntopo.c
index c5ae98a2bb3..b2e909d1f36 100644
--- a/source/blender/blenkernel/intern/dyntopo.c
+++ b/source/blender/blenkernel/intern/dyntopo.c
@@ -3,6 +3,7 @@
 #include "DNA_customdata_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
 
 #include "BLI_array.h"
 #include "BLI_bitmap.h"
@@ -12,6 +13,7 @@
 #include "BLI_ghash.h"
 #include "BLI_heap.h"
 #include "BLI_heap_simple.h"
+#include "BLI_linklist.h"
 #include "BLI_math.h"
 #include "BLI_memarena.h"
 #include "BLI_rand.h"
@@ -140,6 +142,9 @@ static void pbvh_bmesh_verify(PBVH *pbvh);
   } \
   ((void)0)
 
+static bool check_face_is_tri(PBVH *pbvh, BMFace *f);
+static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v);
+
 BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v)
 {
   float co[3];
@@ -1440,6 +1445,122 @@ static void short_edge_queue_task_cb(void *__restrict userdata,
   TGSET_ITER_END
 }
 
+ATTR_NO_OPT static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
+{
+  if (f->len == 3) {
+    return true;
+  }
+
+  if (f->len < 3) {
+    printf("pbvh had < 3 vert face!\n");
+    BKE_pbvh_bmesh_remove_face(pbvh, f, false);
+    return false;
+  }
+
+  BMFace **fs = NULL;
+  BMEdge **es = NULL;
+  LinkNode *dbl = NULL;
+  BLI_array_staticdeclare(fs, 32);
+  BLI_array_staticdeclare(es, 32);
+
+  BKE_pbvh_bmesh_remove_face(pbvh, f, true);
+
+  int len = (f->len - 2) * 3;
+
+  BLI_array_grow_items(fs, len);
+  BLI_array_grow_items(es, len);
+
+  int totface = 0;
+  int totedge = 0;
+  MemArena *arena = NULL;
+  struct Heap *heap = NULL;
+
+  if (f->len > 4) {
+    arena = BLI_memarena_new(512, "ngon arena");
+    heap = BLI_heap_new();
+  }
+
+  BM_face_triangulate(pbvh->bm,
+                      f,
+                      fs,
+                      &totface,
+                      es,
+                      &totedge,
+                      &dbl,
+                      MOD_TRIANGULATE_QUAD_FIXED,
+                      MOD_TRIANGULATE_NGON_BEAUTY,
+                      false,
+                      arena,
+                      heap);
+
+  while (totface && dbl) {
+    BMFace *f = dbl->link;
+    LinkNode *next = dbl->next;
+
+    for (int i = 0; i < totface; i++) {
+      if (fs[i] == f) {
+        fs[i] = NULL;
+      }
+    }
+
+    BM_face_kill(pbvh->bm, dbl->link);
+    MEM_freeN(dbl);
+    dbl = next;
+  }
+
+  for (int i = 0; i < totface; i++) {
+    BMFace *f2 = fs[i];
+
+    if (!f2) {
+      continue;
+    }
+
+    BKE_pbvh_bmesh_add_face(pbvh, f2, true, true);
+  }
+
+  BKE_pbvh_bmesh_add_face(pbvh, f, true, true);
+
+  BLI_array_free(fs);
+  BLI_array_free(es);
+
+  if (arena) {
+    BLI_memarena_free(arena);
+  }
+
+  if (heap) {
+    BLI_heap_free(heap, NULL);
+  }
+
+  return false;
+}
+
+ATTR_NO_OPT static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v)
+{
+  BMFace **fs = NULL;
+  BLI_array_staticdeclare(fs, 32);
+
+  MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+  if (!(mv->flag & DYNVERT_NEED_TRIANGULATE)) {
+    return true;
+  }
+
+  BMIter iter;
+  BMFace *f;
+  BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
+    BLI_array_append(fs, f);
+  }
+
+  mv->flag &= ~DYNVERT_NEED_TRIANGULATE;
+
+  for (int i = 0; i < BLI_array_len(fs); i++) {
+    check_face_is_tri(pbvh, fs[i]);
+  }
+
+  BLI_array_free(fs);
+
+  return false;
+}
+
 /* Create a priority queue containing vertex pairs connected by a long
  * edge as defined by PBVH.bm_max_edge_len.
  *
@@ -1681,6 +1802,9 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
 {
   BMesh *bm = pbvh->bm;
 
+  check_vert_fan_are_tris(pbvh, e->v1);
+  check_vert_fan_are_tris(pbvh, e->v2);
+
   float co_mid[3], no_mid[3];
   MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
   MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
@@ -1968,6 +2092,9 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
 {
   BMVert *v_del, *v_conn;
 
+  check_vert_fan_are_tris(pbvh, e->v1);
+  check_vert_fan_are_tris(pbvh, e->v2);
+
   // customdata interpolation
   if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
     for (int step = 0; step < 2; step++) {
@@ -2409,6 +2536,8 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
         continue;
       }
 
+      check_vert_fan_are_tris(pbvh, v);
+
       const int val = BM_vert_edge_count(v);
       if (val != 4 && val != 3) {
         continue;
@@ -2519,8 +2648,40 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
 
       modified = true;
 
+      if (!v->e) {
+        printf("mesh error!\n");
+        continue;
+      }
+
       l = v->e->l;
 
+      bool flipped = false;
+
+      if (val == 4) {
+        // check which quad diagonal to use to split quad
+        // try to preserve hard edges
+
+        float n1[3], n2[3], th1, th2;
+        normal_tri_v3(n1, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co);
+        normal_tri_v3(n2, ls[0]->v->co, ls[2]->v->co, ls[3]->v->co);
+
+        th1 = dot_v3v3(n1, n2);
+
+        normal_tri_v3(n1, ls[1]->v->co, ls[2]->v->co, ls[3]->v->co);
+        normal_tri_v3(n2, ls[1]->v->co, ls[3]->v->co, ls[0]->v->co);
+
+        th2 = dot_v3v3(n1, n2);
+
+        if (th1 > th2) {
+          flipped = true;
+          BMLoop *ls2[4] = {ls[0], ls[1], ls[2], ls[3]};
+
+          for (int j = 0; j < 4; j++) {
+            ls[j] = ls2[(j + 1) % 4];
+          }
+        }
+      }
+
       vs[0] = ls[0]->v;
       vs[1] = ls[1]->v;
       vs[2] = ls[2]->v;
@@ -2540,11 +2701,15 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
         vs[1] = ls[2]->v;
         vs[2] = ls[3]->v;
 
-        BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, v->e->l->f, false, false);
+        BMFace *example = NULL;
+        if (v->e && v->e->l) {
+          example = v->e->l->f;
+        }
+
+        BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, example, false, false);
 
         CustomData_bmesh_swap_data_simple(
             &pbvh->bm->ldata, &f2->l_first->prev->head.data, &ls[3]->head.data);
-
         CustomData_bmesh_copy_data(
             &pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &f2->l_first->head.data);
         CustomData_bmesh_copy_data(
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 3f846651c9a..e2b082e7996 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1137,7 +1137,8 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
   MDynTopoVert *mv = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
 
   BMEdge *e = v->e;
-  mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY);
+  mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY |
+                DYNVERT_NEED_TRIANGULATE);
 
   if (!e) {
     mv->flag |= DYNVERT_BOUNDARY;
@@ -1155,6 +1156,10 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
         mv->flag |= DYNVERT_FSET_BOUNDARY;
       }
 
+      if (e->l->f->len > 3) {
+        mv->flag |= DYNVERT_NEED_TRIANGULATE;
+      }
+
       lastfset = fset;
       first = false;
 
@@ -1163,6 +1168,10 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
       if (e->l->radial_next != e->l) {
         fset = abs(BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_faceset_offset));
 
+        if (e->l->radial_next->f->len > 3) {
+          mv->flag |= DYNVERT_NEED_TRIANGULATE;
+        }
+
         if (fset != lastfset) {
           mv->flag |= DYNVERT_FSET_BOUNDARY;
         }
@@ -1557,11 +1566,35 @@ BLI_INLINE void pbvh_tribuf_add_vert(PBVHTriBuf *tribuf, SculptVertRef vertex)
   tribuf->verts[tribuf->totvert - 1] = vertex;
 }
 
+BLI_INLINE void pbvh_tribuf_add_edge(PBVHTriBuf *tribuf, int v1, int v2)
+{
+  tribuf->totedge++;
+
+  if (tribuf->totedge >= tribuf->edges_size) {
+    size_t newsize = (size_t)32 + (size_t)(tribuf->edges_size << 1);
+
+    if (!tribuf->edges) {
+      tribuf->edges = MEM_mallocN(sizeof(*tribuf->edges) * 2ULL * newsize, "tribuf edges");
+    }
+    else {
+      tribuf->edges = MEM_reallocN_id(
+          tribuf->edges, sizeof(*tribuf->edges) * 2ULL * newsize, "tribuf edges");
+    }
+
+    tribuf->edges_size = newsize;
+  }
+
+  int i = (tribuf->totedge - 1) * 2;
+
+  tribuf->edges[i] = v1;
+  tribuf->edges[i + 1] = v2;
+}
+
 /* In order to perform operations on the original node coordinates
  * (currently just raycast), store the node's triangles and vertices.
  *
  * Skips triangles that are hidden. */
-bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
+ATTR_NO_OPT bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
 {
   BMesh *bm = pbvh->bm;
 
@@ -1586,6 +1619,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
     node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
   }
 
+  BMLoop **loops = NULL;
+  uint(*loops_idx)[3] = NULL;
+
+  BLI_array_staticdeclare(loops, 128);
+  

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list