Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c115
1 files changed, 111 insertions, 4 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index e14e7004bb1..148f5bf8799 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -618,6 +618,42 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
}
}
+static bool sculpt_vertex_is_boundary(SculptSession *ss, const int index)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES: {
+ const MeshElemMap *vert_map = &ss->pmap[index];
+
+ if (vert_map->count <= 1) {
+ return false;
+ }
+
+ for (int i = 0; i < vert_map->count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ unsigned f_adj_v[2];
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
+ int j;
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ if (!(vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+ case PBVH_BMESH: {
+ BMVert *v = BM_vert_at_index(ss->bm, index);
+ return BM_vert_is_boundary(v);
+ }
+
+ case PBVH_GRIDS:
+ return true;
+ }
+
+ return true;
+}
+
/* Utils */
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
{
@@ -1476,6 +1512,9 @@ static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
if (br->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS) {
return true;
}
+ if (br->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
+ return true;
+ }
return false;
}
@@ -1543,6 +1582,11 @@ static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *au
return NULL;
}
+ const int totvert = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totvert; i++) {
+ ss->cache->automask[i] = 0.0f;
+ }
+
/* Flood fill automask to connected vertices. Limited to vertices inside
* the brush radius if the tool requires it. */
SculptFloodFill flood;
@@ -1579,14 +1623,67 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_vertex_face_set_get(ss, SCULPT_active_vertex_get(ss));
for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
- automask_factor[i] = 1;
+ if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ automask_factor[i] *= 0.0f;
}
- else {
- automask_factor[i] = 0;
+ }
+
+ return automask_factor;
+}
+
+#define EDGE_DISTANCE_INF -1
+
+static float *sculpt_boundary_edges_automasking_init(Sculpt *sd,
+ Object *ob,
+ float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const int propagation_steps = brush->automasking_boundary_edges_propagation_steps;
+
+ if (!sculpt_automasking_enabled(ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Boundary Edges masking: pmap missing");
+ return NULL;
+ }
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
+
+ for (int i = 0; i < totvert; i++) {
+ edge_distance[i] = EDGE_DISTANCE_INF;
+ if (!sculpt_vertex_is_boundary(ss, i)) {
+ edge_distance[i] = 0;
}
}
+ for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
+ for (int i = 0; i < totvert; i++) {
+ if (edge_distance[i] == EDGE_DISTANCE_INF) {
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, i, ni)
+ {
+ if (edge_distance[ni.index] == propagation_it) {
+ edge_distance[i] = propagation_it + 1;
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+ }
+ }
+
+ for (int i = 0; i < totvert; i++) {
+ if (edge_distance[i] != EDGE_DISTANCE_INF) {
+ const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps);
+ const float edge_boundary_automask = 3.0f * p * p - 2.0f * p * p * p;
+ automask_factor[i] *= (1.0f - edge_boundary_automask);
+ }
+ }
+
+ MEM_SAFE_FREE(edge_distance);
return automask_factor;
}
@@ -1594,10 +1691,15 @@ static void sculpt_automasking_init(Sculpt *sd, Object *ob)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
+ const int totvert = SCULPT_vertex_count_get(ss);
ss->cache->automask = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
"automask_factor");
+ for (int i = 0; i < totvert; i++) {
+ ss->cache->automask[i] = 1.0f;
+ }
+
if (brush->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
SCULPT_vertex_random_access_init(ss);
sculpt_topology_automasking_init(sd, ob, ss->cache->automask);
@@ -1606,6 +1708,11 @@ static void sculpt_automasking_init(Sculpt *sd, Object *ob)
SCULPT_vertex_random_access_init(ss);
sculpt_face_sets_automasking_init(sd, ob, ss->cache->automask);
}
+
+ if (brush->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
+ SCULPT_vertex_random_access_init(ss);
+ sculpt_boundary_edges_automasking_init(sd, ob, ss->cache->automask);
+ }
}
/* ===== Sculpting =====