[Bf-blender-cvs] [b5100e73c8e] temp_bmesh_multires: Sculpt dyntopo: Fix boundary brush for multires

Joseph Eagar noreply at git.blender.org
Mon Aug 16 10:52:59 CEST 2021


Commit: b5100e73c8e868febe8c850ce299b24d1dc88bd4
Author: Joseph Eagar
Date:   Mon Aug 16 01:44:31 2021 -0700
Branches: temp_bmesh_multires
https://developer.blender.org/rBb5100e73c8e868febe8c850ce299b24d1dc88bd4

Sculpt dyntopo: Fix boundary brush for multires

This commit fixes boundary brush for multires which
broke two commits ago.

This required implementing the geodesic api for PBVH_GRIDS,
which I did by building topology maps in a rather. . .
haphazard fashion.

Basically I built a vert->edge map and then used it to
derive a pseudo edge to quads mapping (it maps edges
to all the verts in the two surrounding quads except
the edge's own verts).

Just for fun I enabled geodesic mode in mask expand;
it seems to work.

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

M	release/scripts/addons
M	source/blender/editors/sculpt_paint/sculpt_boundary.c
M	source/blender/editors/sculpt_paint/sculpt_expand.c
M	source/blender/editors/sculpt_paint/sculpt_geodesic.c
M	source/tools

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

diff --git a/release/scripts/addons b/release/scripts/addons
index 78107f78694..985f6d8c304 160000
--- a/release/scripts/addons
+++ b/release/scripts/addons
@@ -1 +1 @@
-Subproject commit 78107f78694f47ee6e50a7eb7c16b506af921199
+Subproject commit 985f6d8c304630c155133e9b368fdb7a29cac216
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 1138da97ac8..9efc4dece8e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -421,7 +421,7 @@ static float *calc_boundary_tangent(SculptSession *ss, SculptBoundary *boundary)
   return (float *)tangents;
 }
 
-ATTR_NO_OPT static void sculpt_boundary_cotan_init(SculptSession *ss, SculptBoundary *boundary)
+static void sculpt_boundary_cotan_init(SculptSession *ss, SculptBoundary *boundary)
 {
   const int totvert = SCULPT_vertex_count_get(ss);
   boundary->boundary_cotangents = MEM_calloc_arrayN(
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 29e162fb219..1e8c476920e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -930,7 +930,7 @@ static void sculpt_expand_geodesics_from_state_boundary(Object *ob,
                                                         BLI_bitmap *enabled_vertices)
 {
   SculptSession *ss = ob->sculpt;
-  BLI_assert(ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH));
+  BLI_assert(ELEM(BKE_pbvh_type(ss->pbvh), PBVH_GRIDS, PBVH_FACES, PBVH_BMESH));
 
   GSet *initial_vertices = BLI_gset_int_new("initial_vertices");
   BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(ss, enabled_vertices, false);
@@ -1051,7 +1051,7 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
     BLI_BITMAP_ENABLE(enabled_vertices, i);
   }
 
-  if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH)) {
+  if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_GRIDS, PBVH_FACES, PBVH_BMESH)) {
     sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_vertices);
   }
   else {
@@ -1112,9 +1112,12 @@ static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(
 
   switch (falloff_type) {
     case SCULPT_EXPAND_FALLOFF_GEODESIC:
+      expand_cache->vert_falloff = sculpt_expand_geodesic_falloff_create(sd, ob, v);
+      /*
       expand_cache->vert_falloff = has_topology_info ?
                                        sculpt_expand_geodesic_falloff_create(sd, ob, v) :
                                        sculpt_expand_spherical_falloff_create(ob, v);
+                                       */
       break;
     case SCULPT_EXPAND_FALLOFF_TOPOLOGY:
       expand_cache->vert_falloff = sculpt_expand_topology_falloff_create(sd, ob, v);
diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c
index 691f2e6d93f..ecdbbe9280e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_geodesic.c
+++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c
@@ -23,10 +23,16 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "BLI_alloca.h"
+#include "BLI_array.h"
 #include "BLI_blenlib.h"
 #include "BLI_linklist_stack.h"
 #include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_sort_utils.h"
 #include "BLI_task.h"
+#include "BLI_utildefines.h"
 
 #include "BLT_translation.h"
 
@@ -144,6 +150,80 @@ static bool sculpt_geodesic_mesh_test_dist_add(MVert *mvert,
   return false;
 }
 
+/* Propagate distance from v1 and v2 to v0. */
+static bool sculpt_geodesic_grids_test_dist_add(SculptSession *ss,
+                                                const int v0,
+                                                const int v1,
+                                                const int v2,
+                                                float *dists,
+                                                GSet *initial_vertices,
+                                                SculptVertRef *r_closest_verts,
+                                                float (*cos)[3])
+{
+  if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(v0))) {
+    return false;
+  }
+
+  BLI_assert(dists[v1] != FLT_MAX);
+  if (dists[v0] <= dists[v1]) {
+    return false;
+  }
+
+  const float *co0 = cos ? cos[v0] :
+                           SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, v0));
+  const float *co1 = cos ? cos[v1] :
+                           SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, v1));
+  const float *co2 = v2 != SCULPT_GEODESIC_VERTEX_NONE ?
+                         (cos ? cos[v2] :
+                                SCULPT_vertex_co_get(
+                                    ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, v2))) :
+                         NULL;
+
+  float dist0;
+  if (v2 != SCULPT_GEODESIC_VERTEX_NONE) {
+    BLI_assert(dists[v2] != FLT_MAX);
+    if (dists[v0] <= dists[v2]) {
+      return false;
+    }
+    dist0 = geodesic_distance_propagate_across_triangle(co0, co1, co2, dists[v1], dists[v2]);
+  }
+  else {
+    float vec[3];
+    sub_v3_v3v3(vec, co1, co0);
+    dist0 = dists[v1] + len_v3(vec);
+  }
+
+  if (dist0 < dists[v0]) {
+    dists[v0] = dist0;
+
+    if (r_closest_verts) {
+      bool tag1 = r_closest_verts[v1].i != -1LL;
+      bool tag2 = v2 != SCULPT_GEODESIC_VERTEX_NONE && r_closest_verts[v2].i != -1LL;
+
+      float l1 = len_v3v3(co0, co1);
+      float l2 = v2 != SCULPT_GEODESIC_VERTEX_NONE ? len_v3v3(co0, co2) : 0.0f;
+
+      if (tag1 && tag2) {
+        if (l1 < l2) {
+          r_closest_verts[v0] = r_closest_verts[v1];
+        }
+        else {
+          r_closest_verts[v0] = r_closest_verts[v2];
+        }
+      }
+      else if (tag2) {
+        r_closest_verts[v0] = r_closest_verts[v2];
+      }
+      else if (tag1) {
+        r_closest_verts[v0] = r_closest_verts[v1];
+      }
+    }
+    return true;
+  }
+
+  return false;
+}
+
 #define BMESH_INITIAL_VERT_TAG BM_ELEM_TAG_ALT
 
 static bool sculpt_geodesic_mesh_test_dist_add_bmesh(BMVert *v0,
@@ -598,6 +678,302 @@ static float *SCULPT_geodesic_bmesh_create(Object *ob,
   return dists;
 }
 
+BLI_INLINE void *hash_edge(int v1, int v2, int totvert)
+{
+  if (v1 > v2) {
+    SWAP(int, v1, v2);
+  }
+
+  intptr_t ret = (intptr_t)v1 + (intptr_t)v2 * (intptr_t)totvert;
+  return (void *)ret;
+}
+
+typedef struct TempEdge {
+  int v1, v2;
+} TempEdge;
+
+int find_quad(TempEdge *edges, MeshElemMap *vmap, int v1, int v2, int v3)
+{
+  for (int i = 0; i < vmap[v1].count; i++) {
+    TempEdge *te = edges + vmap[v1].indices[i];
+    int v = v1 == te->v1 ? te->v2 : te->v1;
+
+    if (v == v2) {
+      continue;
+    }
+
+    for (int j = 0; j < vmap[v].count; j++) {
+      TempEdge *te2 = edges + vmap[v].indices[j];
+      int v4 = v == te2->v1 ? te2->v2 : te2->v1;
+
+      if (v4 == v3) {
+        return v;
+      }
+    }
+  }
+
+  return -1;
+}
+
+static float *SCULPT_geodesic_grids_create(Object *ob,
+                                           GSet *initial_vertices,
+                                           const float limit_radius,
+                                           SculptVertRef *r_closest_verts,
+                                           float (*cos)[3])
+{
+  SculptSession *ss = ob->sculpt;
+  Mesh *mesh = BKE_object_get_original_mesh(ob);
+
+  const int totvert = SCULPT_vertex_count_get(ss);
+
+  const float limit_radius_sq = limit_radius * limit_radius;
+
+  float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances");
+
+  /* Both contain edge indices encoded as *void. */
+  BLI_LINKSTACK_DECLARE(queue, void *);
+  BLI_LINKSTACK_DECLARE(queue_next, void *);
+
+  BLI_LINKSTACK_INIT(queue);
+  BLI_LINKSTACK_INIT(queue_next);
+
+  for (int i = 0; i < totvert; i++) {
+    if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(i))) {
+      if (r_closest_verts) {
+        r_closest_verts[i] = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+      }
+
+      dists[i] = 0.0f;
+    }
+    else {
+      if (r_closest_verts) {
+        r_closest_verts[i].i = -1LL;
+      }
+
+      dists[i] = FLT_MAX;
+    }
+  }
+
+  /* Masks vertices that are further than limit radius from an initial vertex. As there is no need
+   * to define a distance to them the algorithm can stop earlier by skipping them. */
+  BLI_bitmap *affected_vertex = BLI_BITMAP_NEW(totvert, "affected vertex");
+  GSetIterator gs_iter;
+
+  if (limit_radius == FLT_MAX) {
+    /* In this case, no need to loop through all initial vertices to check distances as they are
+     * all going to be affected. */
+    BLI_bitmap_set_all(affected_vertex, true, totvert);
+  }
+  else {
+    /* This is an O(n^2) loop used to limit the geodesic distance calculation to a radius. When
+     * this optimization is needed, it is expected for the tool to request the distance to a low
+     * number of vertices (usually just 1 or 2). */
+    GSET_ITER (gs_iter, initial_vertices) {
+      const int v = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
+      SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, v);
+      const float *v_co = cos ? cos[v] : SCULPT_vertex_co_get(ss, vertex);
+
+      for (int i = 0; i < totvert; i++) {
+        const float *v_co2 = cos ? cos[i] :
+                                   SCULPT_vertex_co_get(
+                                       ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i));
+        if (len_squared_v3v3(v_co, v_co2) <= limit_radius_sq) {
+          BLI_BITMAP_ENABLE(affected_vertex, i);
+        }
+      }
+    }
+  }
+
+  SculptVertexNeighborIter ni;
+
+  TempEdge *edges = NULL;
+  BLI_array_declare(edges);
+  GHash *ehash = BLI_ghash_ptr_new("geodesic multigrids ghash");
+
+  MeshElemMap *vmap = MEM_calloc_arrayN(totvert, sizeof(*vmap), "geodesic grids vmap");
+
+  int totedge = 0;
+  MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "geodesic grids memarena");
+
+  for (int i = 0; i < totvert; i++) {
+    SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+    MeshElemMap *map = vmap + i;
+
+    int val = SCULPT_vert

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list