diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index 7f3f0f70d35..5533316c315 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -435,6 +435,10 @@ class FalloffPanel(BrushPanel): return col = layout.column(align=True) + row = col.row(align=True) + row.prop(brush, "flatten_hardness", slider=True, text="Flatten hardness") + row.prop(brush, "flatten_depth", slider=True, text="Flatten depth") + row = col.row(align=True) row.prop(brush, "curve_preset", text="") diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 3e45f6db5e5..4b698e38e95 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -1751,6 +1751,9 @@ void BKE_brush_debug_print_state(Brush *br) BR_TEST(plane_trim, f); + BR_TEST(flatten_hardness, f); + BR_TEST(flatten_depth, f); + BR_TEST(texture_sample_bias, f); BR_TEST(texture_overlay_alpha, d); diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 56b12ce6716..16c7e57e88a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -3050,14 +3050,31 @@ void SCULPT_calc_brush_plane( } } -int SCULPT_plane_trim(const blender::ed::sculpt_paint::StrokeCache *cache, - const Brush *brush, - const float val[3]) +bool SCULPT_plane_trim(const blender::ed::sculpt_paint::StrokeCache *cache, + const Brush *brush, + const float val[3]) { return (!(brush->flag & BRUSH_PLANE_TRIM) || (dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)); } +float SCULPT_flatten_hardness(const blender::ed::sculpt_paint::StrokeCache *cache, + const float val[3]) +{ + /* if the vertex is over the sculpt plane, no adjusted fallof is applied. */ + if (dot_v3v3(val, cache->sculpt_normal) < 0) { + return 1.0; + } + /* Workaround for https://projects.blender.org/blender/blender/issues/116458 + apply a falloff based on the distance to the brush plane */ + float len = len_v3(val); + const float threshold = cache->radius * cache->flatten_depth; + if (len > threshold) { + return 0.f; + } + return (1.0f - len / threshold) * cache->flatten_hardness; +} + int SCULPT_plane_point_side(const float co[3], const float plane[4]) { float d = plane_point_side_v3(plane, co); @@ -4211,6 +4228,8 @@ static void sculpt_update_cache_invariants( cache->scale[2] = max_scale / ob->scale[2]; cache->plane_trim_squared = brush->plane_trim * brush->plane_trim; + cache->flatten_hardness = brush->flatten_hardness; + cache->flatten_depth = brush->flatten_depth; cache->flag = 0; diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.cc b/source/blender/editors/sculpt_paint/sculpt_brush_types.cc index 4e58d7a45b9..d9559e523ae 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.cc +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.cc @@ -373,18 +373,17 @@ static void do_fill_brush_task( } auto_mask::node_update(automask_data, vd); - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask, - vd.vertex, - thread_id, - &automask_data); - + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask, + vd.vertex, + thread_id, + &automask_data); + fade *= SCULPT_flatten_hardness(ss->cache, val); mul_v3_v3fl(proxy[vd.i], val, fade); } BKE_pbvh_vertex_iter_end; @@ -461,18 +460,17 @@ static void do_scrape_brush_task( } auto_mask::node_update(automask_data, vd); - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask, - vd.vertex, - thread_id, - &automask_data); - + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask, + vd.vertex, + thread_id, + &automask_data); + fade *= SCULPT_flatten_hardness(ss->cache, val); mul_v3_v3fl(proxy[vd.i], val, fade); } BKE_pbvh_vertex_iter_end; @@ -706,17 +704,17 @@ static void do_flatten_brush_task( if (SCULPT_plane_trim(ss->cache, brush, val)) { auto_mask::node_update(automask_data, vd); - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask, - vd.vertex, - thread_id, - &automask_data); - + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask, + vd.vertex, + thread_id, + &automask_data); + fade *= SCULPT_flatten_hardness(ss->cache, val); mul_v3_v3fl(proxy[vd.i], val, fade); } } @@ -955,17 +953,17 @@ static void do_clay_strips_brush_task(Object *ob, auto_mask::node_update(automask_data, vd); /* The normal from the vertices is ignored, it causes glitch with planes, see: #44390. */ - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - ss->cache->radius * test.dist, - vd.no, - vd.fno, - vd.mask, - vd.vertex, - thread_id, - &automask_data); - + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + ss->cache->radius * test.dist, + vd.no, + vd.fno, + vd.mask, + vd.vertex, + thread_id, + &automask_data); + fade *= SCULPT_flatten_hardness(ss->cache, val); mul_v3_v3fl(proxy[vd.i], val, fade); } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index f4b3a5c6b23..455d155858a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -520,6 +520,8 @@ struct StrokeCache { bool alt_smooth; float plane_trim_squared; + float flatten_hardness; + float flatten_depth; bool supports_gravity; float3 true_gravity_direction; @@ -1048,9 +1050,12 @@ PBVHVertRef SCULPT_nearest_vertex_get(Object *ob, bool use_original); int SCULPT_plane_point_side(const float co[3], const float plane[4]); -int SCULPT_plane_trim(const blender::ed::sculpt_paint::StrokeCache *cache, - const Brush *brush, - const float val[3]); +bool SCULPT_plane_trim(const blender::ed::sculpt_paint::StrokeCache *cache, + const Brush *brush, + const float val[3]); + +float SCULPT_flatten_hardness(const blender::ed::sculpt_paint::StrokeCache *cache, + const float val[3]); /** * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.cc b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.cc index aae52719077..d872102b73b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.cc +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.cc @@ -170,17 +170,18 @@ static void do_multiplane_scrape_brush_task(Object *ob, /* Deform the local space along the Y axis to avoid artifacts on curved strokes. */ /* This produces a not round brush tip. */ local_co[1] *= 2.0f; - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - len_v3(local_co), - vd.no, - vd.fno, - vd.mask, - vd.vertex, - thread_id, - &automask_data); + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + len_v3(local_co), + vd.no, + vd.fno, + vd.mask, + vd.vertex, + thread_id, + &automask_data); + fade *= SCULPT_flatten_hardness(ss->cache, val); mul_v3_v3fl(proxy[vd.i], val, fade); } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h index bd88d4ac6d7..6887b0e8765 100644 --- a/source/blender/makesdna/DNA_brush_defaults.h +++ b/source/blender/makesdna/DNA_brush_defaults.h @@ -44,6 +44,8 @@ /* How far above or below the plane that is found by averaging the faces. */ \ .plane_offset = 0.0f, \ .plane_trim = 0.5f, \ + .flatten_hardness = 1.0f, \ + .flatten_depth = 1.0f, \ .clone.alpha = 0.5f, \ .normal_weight = 0.0f, \ .fill_threshold = 0.2f, \ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index f4800083f53..63fcd6e7cf1 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -306,6 +306,10 @@ typedef struct Brush { float wet_paint_radius_factor; float plane_trim; + + /* Affect depth and strenght of the brush's effect */ + float flatten_hardness; + float flatten_depth; /** Affectable height of brush (layer height for layer tool, i.e.). */ float height; diff --git a/source/blender/makesrna/intern/rna_brush.cc b/source/blender/makesrna/intern/rna_brush.cc index 22a1d676bc5..157d3e2af37 100644 --- a/source/blender/makesrna/intern/rna_brush.cc +++ b/source/blender/makesrna/intern/rna_brush.cc @@ -3011,6 +3011,23 @@ static void rna_def_brush(BlenderRNA *brna) "If a vertex is further away from offset plane than this, then it is not affected"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "flatten_hardness", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, nullptr, "flatten_hardness"); + RNA_def_property_range(prop, 0, 1.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text( + prop, + "Flatten hardness", + "How strong the flattening effect is"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "flatten_depth", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, nullptr, "flatten_depth"); + RNA_def_property_range(prop, 0, 1.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Flatten depth", "Depth limit on the flattening effect, from 0 to 1 (radius)"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, nullptr, "height"); RNA_def_property_float_default(prop, 0.5f);