[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