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:
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py5
-rw-r--r--source/blender/blenloader/intern/versioning_280.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c115
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_brush_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_brush.c16
6 files changed, 145 insertions, 6 deletions
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index df3dc930f97..b50791050c4 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -813,6 +813,11 @@ def brush_settings_advanced(layout, context, brush, popover=False):
# face masks automasking
layout.prop(brush, "use_automasking_face_sets")
+
+ # boundary edges automasking
+ layout.prop(brush, "use_automasking_boundary_edges")
+ layout.prop(brush, "automasking_boundary_edges_propagation_steps")
+
# sculpt plane settings
if capabilities.has_sculpt_plane:
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 68f0abe9b3e..2d1c57b1495 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -4811,5 +4811,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Boundary Edges Automasking. */
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "Brush", "int", "automasking_boundary_edges_propagation_steps")) {
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ br->automasking_boundary_edges_propagation_steps = 1;
+ }
+ }
}
}
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 =====
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index 1182631a82b..f315cc4b8a0 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -103,6 +103,7 @@
.pose_smooth_iterations = 4, \
.pose_ik_segments = 1, \
.hardness = 0.0f, \
+ .automasking_boundary_edges_propagation_steps = 1, \
\
/* A kernel radius of 1 has almost no effect (T63233). */ \
.blur_kernel_radius = 2, \
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3f703558e54..2168a63940f 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -321,6 +321,7 @@ typedef enum eGP_Sculpt_Mode_Flag {
typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0),
BRUSH_AUTOMASKING_FACE_SETS = (1 << 1),
+ BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2),
} eAutomasking_flag;
typedef struct Brush {
@@ -426,7 +427,7 @@ typedef struct Brush {
char gpencil_sculpt_tool;
/** Active grease pencil weight tool. */
char gpencil_weight_tool;
- char _pad1_[6];
+ char _pad1[6];
float autosmooth_factor;
@@ -446,7 +447,9 @@ typedef struct Brush {
int curve_preset;
float hardness;
+ /* automasking */
int automasking_flags;
+ int automasking_boundary_edges_propagation_steps;
/* Factor that controls the shape of the brush tip by rounding the corners of a square. */
/* 0.0 value produces a square, 1.0 produces a circle. */
@@ -497,7 +500,6 @@ typedef struct Brush {
float mask_stencil_pos[2];
float mask_stencil_dimension[2];
- char _pad6[4];
struct BrushGpencilSettings *gpencil_settings;
} Brush;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 39216009e34..5ea1b696e49 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -2169,6 +2169,17 @@ static void rna_def_brush(BlenderRNA *brna)
prop, "Hardness", "How close the brush falloff starts from the edge of the brush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(
+ srna, "automasking_boundary_edges_propagation_steps", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "automasking_boundary_edges_propagation_steps");
+ RNA_def_property_range(prop, 1, 20);
+ RNA_def_property_ui_range(prop, 1, 20, 1, 3);
+ RNA_def_property_ui_text(prop,
+ "Propagation Steps",
+ "Distance where boundary edge automaking is going to protect vertices "
+ "from the fully masked edge");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);
@@ -2309,6 +2320,11 @@ static void rna_def_brush(BlenderRNA *brna)
"Affect only vertices that share Face Sets with the active vertex");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_automasking_boundary_edges", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_EDGES);
+ RNA_def_property_ui_text(prop, "Edges Automasking", "Do not affect non manifold boundary edges");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_scene_spacing", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, brush_spacing_unit_items);