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.py17
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py15
-rw-r--r--source/blender/blenkernel/BKE_paint.h17
-rw-r--r--source/blender/blenkernel/intern/paint.cc8
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c94
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc296
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c35
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c240
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c34
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.cc15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c16
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c120
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h52
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c20
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c32
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_image.cc18
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c36
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c5
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c2
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_brush.c22
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c57
27 files changed, 1049 insertions, 129 deletions
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index a4a328fce1a..72a87703bd5 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -945,10 +945,27 @@ def brush_settings_advanced(layout, context, brush, popover=False):
col.prop(brush, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
col.prop(brush, "use_automasking_cavity", text="Cavity")
col.prop(brush, "use_automasking_cavity_inverted", text="Cavity (Inverted)")
+ col.prop(brush, "use_automasking_start_normal", text="Area Normal")
+ col.prop(brush, "use_automasking_view_normal", text="View Normal")
col.separator()
col.prop(brush, "automasking_boundary_edges_propagation_steps")
+ sculpt = context.tool_settings.sculpt
+
+ if brush.use_automasking_start_normal:
+ col.separator()
+
+ col.prop(sculpt, "automasking_start_normal_limit")
+ col.prop(sculpt, "automasking_start_normal_falloff")
+
+ if brush.use_automasking_view_normal:
+ col.separator()
+
+ col.prop(brush, "use_automasking_view_occlusion", text="Occlusion")
+ col.prop(sculpt, "automasking_view_normal_limit")
+ col.prop(sculpt, "automasking_view_normal_falloff")
+
if brush.use_automasking_cavity or brush.use_automasking_cavity_inverted:
col.separator()
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index fcf00ee80f6..ada2993a16f 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -5497,6 +5497,8 @@ class VIEW3D_MT_sculpt_automasking_pie(Menu):
pie.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
pie.prop(sculpt, "use_automasking_cavity", text="Cavity")
pie.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (Inverted)")
+ pie.prop(sculpt, "use_automasking_start_normal", text="Area Normal")
+ pie.prop(sculpt, "use_automasking_view_normal", text="View Normal")
class VIEW3D_MT_sculpt_face_sets_edit_pie(Menu):
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index d18b75e78af..6946ab54ca7 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -974,6 +974,21 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
col.prop(sculpt, "use_automasking_cavity", text="Cavity")
col.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (Inverted)")
+ col.prop(sculpt, "use_automasking_start_normal", text="Area Normal")
+ col.prop(sculpt, "use_automasking_view_normal", text="View Normal")
+
+ if sculpt.use_automasking_start_normal:
+ col.separator()
+
+ col.prop(sculpt, "automasking_start_normal_limit")
+ col.prop(sculpt, "automasking_start_normal_falloff")
+
+ if sculpt.use_automasking_view_normal:
+ col.separator()
+
+ col.prop(sculpt, "use_automasking_view_occlusion", text="Occlusion")
+ col.prop(sculpt, "automasking_view_normal_limit")
+ col.prop(sculpt, "automasking_view_normal_falloff")
col.separator()
col.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps")
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 386fecfd278..ed7ef5d5efd 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -474,11 +474,6 @@ typedef struct SculptBoundary {
} twist;
} SculptBoundary;
-typedef struct CavityMaskData {
- float factor;
- int stroke_id;
-} CavityMaskData;
-
typedef struct SculptFakeNeighbors {
bool use_fake_neighbors;
@@ -554,13 +549,13 @@ typedef struct SculptAttributePointers {
/* Precomputed auto-mask factor indexed by vertex, owned by the auto-masking system and
* initialized in #SCULPT_automasking_cache_init when needed. */
SculptAttribute *automasking_factor;
+ SculptAttribute *automasking_occlusion; /* CD_PROP_INT8. */
+ SculptAttribute *automasking_stroke_id;
+ SculptAttribute *automasking_cavity;
/* BMesh */
SculptAttribute *dyntopo_node_id_vertex;
SculptAttribute *dyntopo_node_id_face;
-
- SculptAttribute *stroke_id;
- SculptAttribute *cavity;
} SculptAttributePointers;
typedef struct SculptSession {
@@ -747,14 +742,16 @@ typedef struct SculptSession {
*/
bool sticky_shading_color;
+ uchar stroke_id;
+
/**
* Last used painting canvas key.
*/
char *last_paint_canvas_key;
+ float last_normal[3];
- uchar stroke_id;
int last_automasking_settings_hash;
- uchar last_cavity_stroke_id;
+ uchar last_automask_stroke_id;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index 08e49550426..e0a27a3d03e 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -2079,6 +2079,14 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene)
sd->constant_detail = 3.0f;
}
+ if (!sd->automasking_start_normal_limit) {
+ sd->automasking_start_normal_limit = 20.0f / 180.0f * M_PI;
+ sd->automasking_start_normal_falloff = 0.25f;
+
+ sd->automasking_view_normal_limit = 90.0f / 180.0f * M_PI;
+ sd->automasking_view_normal_falloff = 0.25f;
+ }
+
/* Set sane default tiling offsets. */
if (!sd->paint.tile_offset[0]) {
sd->paint.tile_offset[0] = 1.0f;
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 1e220d33ff4..59b2d8d31b9 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -34,7 +34,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
/* sculpt_transform.c */
void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob);
-void ED_sculpt_init_transform(struct bContext *C, struct Object *ob, const char *undo_name);
+void ED_sculpt_init_transform(struct bContext *C, struct Object *ob, const int mval[2], const char *undo_name);
void ED_sculpt_end_transform(struct bContext *C, struct Object *ob);
/* sculpt_undo.c */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 54810436d20..7fc5df8237a 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1268,11 +1268,11 @@ static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush
/**
* Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
*/
-static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush)
+static int sculpt_brush_needs_normal(const SculptSession *ss, Sculpt *sd, const Brush *brush)
{
return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
(ss->cache->normal_weight > 0.0f)) ||
-
+ SCULPT_automasking_needs_normal(ss, sd, brush) ||
ELEM(brush->sculpt_tool,
SCULPT_TOOL_BLOB,
SCULPT_TOOL_CREASE,
@@ -2413,7 +2413,8 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
const float fno[3],
float mask,
const PBVHVertRef vertex,
- int thread_id)
+ const int thread_id,
+ AutomaskingNodeData *automask_data)
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
@@ -2497,7 +2498,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
avg *= 1.0f - mask;
/* Auto-masking. */
- avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex);
+ avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex, automask_data);
return avg;
}
@@ -3087,7 +3088,8 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ NULL);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3396,7 +3398,7 @@ static void do_brush_action(Sculpt *sd,
BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
}
- if (sculpt_brush_needs_normal(ss, brush)) {
+ if (sculpt_brush_needs_normal(ss, sd, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
}
@@ -3548,7 +3550,7 @@ static void do_brush_action(Sculpt *sd,
SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
}
- if (!SCULPT_tool_can_reuse_cavity_mask(brush->sculpt_tool) ||
+ if (!SCULPT_tool_can_reuse_automask(brush->sculpt_tool) ||
(ss->cache->supports_gravity && sd->gravity_factor > 0.0f)) {
/* Clear cavity mask cache. */
ss->last_automasking_settings_hash = 0;
@@ -4242,8 +4244,6 @@ static void sculpt_update_cache_invariants(
ss->cache = cache;
- cache->stroke_id = ss->stroke_id;
-
/* Set scaling adjustment. */
max_scale = 0.0f;
for (int i = 0; i < 3; i++) {
@@ -5413,6 +5413,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
}
SCULPT_stroke_id_next(ob);
+ ss->cache->stroke_id = ss->stroke_id;
return true;
}
@@ -6012,6 +6013,70 @@ void SCULPT_fake_neighbors_free(Object *ob)
sculpt_pose_fake_neighbors_free(ss);
}
+void SCULPT_automasking_node_begin(Object *ob,
+ const SculptSession *UNUSED(ss),
+ AutomaskingCache *automasking,
+ AutomaskingNodeData *node_data,
+ PBVHNode *node)
+{
+ if (!automasking) {
+ memset(node_data, 0, sizeof(*node_data));
+ return;
+ }
+
+ node_data->node = node;
+ node_data->have_orig_data = automasking->settings.flags &
+ (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL);
+
+ if (node_data->have_orig_data) {
+ SCULPT_orig_vert_data_init(&node_data->orig_data, ob, node, SCULPT_UNDO_COORDS);
+ }
+ else {
+ memset(&node_data->orig_data, 0, sizeof(node_data->orig_data));
+ }
+}
+
+void SCULPT_automasking_node_update(SculptSession *UNUSED(ss),
+ AutomaskingNodeData *automask_data,
+ PBVHVertexIter *vd)
+{
+ if (automask_data->have_orig_data) {
+ SCULPT_orig_vert_data_update(&automask_data->orig_data, vd);
+ }
+}
+
+bool SCULPT_vertex_is_occluded(SculptSession *ss, PBVHVertRef vertex, bool original)
+{
+ float ray_start[3], ray_end[3], ray_normal[3], face_normal[3];
+ float co[3];
+
+ copy_v3_v3(co, SCULPT_vertex_co_get(ss, vertex));
+ float mouse[2];
+
+ ED_view3d_project_float_v2_m4(ss->cache->vc->region, co, mouse, ss->cache->projection_mat);
+
+ int depth = SCULPT_raycast_init(ss->cache->vc, mouse, ray_end, ray_start, ray_normal, original);
+
+ negate_v3(ray_normal);
+
+ copy_v3_v3(ray_start, SCULPT_vertex_co_get(ss, vertex));
+ madd_v3_v3fl(ray_start, ray_normal, 0.002);
+
+ SculptRaycastData srd = {0};
+ srd.original = original;
+ srd.ss = ss;
+ srd.hit = false;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.depth = depth;
+ srd.face_normal = face_normal;
+
+ isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
+ BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
+
+ return srd.hit;
+}
+
void SCULPT_stroke_id_next(Object *ob)
{
/* Manually wrap in int32 space to avoid tripping up undefined behavior
@@ -6024,11 +6089,14 @@ void SCULPT_stroke_id_ensure(Object *ob)
{
SculptSession *ss = ob->sculpt;
- if (!ss->attrs.stroke_id) {
+ if (!ss->attrs.automasking_stroke_id) {
SculptAttributeParams params = {0};
-
- ss->attrs.stroke_id = BKE_sculpt_attribute_ensure(
- ob, ATTR_DOMAIN_POINT, CD_PROP_INT8, SCULPT_ATTRIBUTE_NAME(stroke_id), &params);
+ ss->attrs.automasking_stroke_id = BKE_sculpt_attribute_ensure(
+ ob,
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT8,
+ SCULPT_ATTRIBUTE_NAME(automasking_stroke_id),
+ &params);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index 43225443ea0..100eb69ac48 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -98,6 +98,12 @@ bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, co
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
return true;
}
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BRUSH_NORMAL)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_VIEW_NORMAL)) {
+ return true;
+ }
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_CAVITY_ALL)) {
return true;
}
@@ -127,6 +133,50 @@ static int sculpt_automasking_mode_effective_bits(const Sculpt *sculpt, const Br
return sculpt->automasking_flags;
}
+bool SCULPT_automasking_needs_normal(const SculptSession *UNUSED(ss),
+ const Sculpt *sculpt,
+ const Brush *brush)
+{
+ int flags = sculpt_automasking_mode_effective_bits(sculpt, brush);
+
+ return flags & (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL);
+}
+
+static float sculpt_automasking_normal_calc(SculptSession *ss,
+ PBVHVertRef vertex,
+ float3 &normal,
+ float limit_lower,
+ float limit_upper,
+ AutomaskingNodeData *automask_data)
+{
+ float3 normal_v;
+
+ if (automask_data->have_orig_data) {
+ normal_v = automask_data->orig_data.no;
+ }
+ else {
+ SCULPT_vertex_normal_get(ss, vertex, normal_v);
+ }
+
+ float angle = saacos(dot_v3v3(normal, normal_v));
+
+ /* note that limit is pre-divided by M_PI */
+
+ if (angle > limit_lower && angle < limit_upper) {
+ float t = 1.0f - (angle - limit_lower) / (limit_upper - limit_lower);
+
+ /* smoothstep */
+ t = t * t * (3.0 - 2.0 * t);
+
+ return t;
+ }
+ else if (angle > limit_upper) {
+ return 0.0f;
+ }
+
+ return 1.0f;
+}
+
static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush *brush)
{
@@ -134,13 +184,93 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
return true;
}
+
if (automasking_flags &
- (BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS | BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
+ (BRUSH_AUTOMASKING_BOUNDARY_EDGES | BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS |
+ BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL)) {
return brush && brush->automasking_boundary_edges_propagation_steps != 1;
}
return false;
}
+static float automasking_brush_normal_factor(AutomaskingCache *automasking,
+ SculptSession *ss,
+ PBVHVertRef vertex,
+ AutomaskingNodeData *automask_data)
+{
+ float falloff = automasking->settings.start_normal_falloff * M_PI;
+ float3 initial_normal;
+
+ if (ss->cache) {
+ initial_normal = ss->cache->initial_normal;
+ }
+ else {
+ initial_normal = ss->filter_cache->initial_normal;
+ }
+
+ return sculpt_automasking_normal_calc(ss,
+ vertex,
+ initial_normal,
+ automasking->settings.start_normal_limit - falloff * 0.5f,
+ automasking->settings.start_normal_limit + falloff * 0.5f,
+ automask_data);
+}
+
+static float automasking_view_normal_factor(AutomaskingCache *automasking,
+ SculptSession *ss,
+ PBVHVertRef vertex,
+ AutomaskingNodeData *automask_data)
+{
+ float falloff = automasking->settings.view_normal_falloff * M_PI;
+
+ float3 view_normal;
+
+ if (ss->cache) {
+ view_normal = ss->cache->view_normal;
+ }
+ else {
+ view_normal = ss->filter_cache->view_normal;
+ }
+
+ return sculpt_automasking_normal_calc(ss,
+ vertex,
+ view_normal,
+ automasking->settings.view_normal_limit,
+ automasking->settings.view_normal_limit + falloff,
+ automask_data);
+}
+
+static float automasking_view_occlusion_factor(AutomaskingCache *automasking,
+ SculptSession *ss,
+ PBVHVertRef vertex,
+ uchar stroke_id,
+ AutomaskingNodeData *UNUSED(automask_data))
+{
+ char f = *(char *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_occlusion);
+
+ if (stroke_id != automasking->current_stroke_id) {
+ f = *(char *)SCULPT_vertex_attr_get(
+ vertex,
+ ss->attrs.automasking_occlusion) = SCULPT_vertex_is_occluded(ss, vertex, true) ? 2 : 1;
+ }
+
+ return f == 2;
+}
+
+/* Updates vertex stroke id. */
+static float automasking_factor_end(SculptSession *ss,
+ AutomaskingCache *automasking,
+ PBVHVertRef vertex,
+ float value)
+{
+ if (ss->attrs.automasking_stroke_id) {
+ *(uchar *)SCULPT_vertex_attr_get(
+ vertex, ss->attrs.automasking_stroke_id) = automasking->current_stroke_id;
+ }
+
+ return value;
+}
+
static float sculpt_cavity_calc_factor(AutomaskingCache *automasking, float factor)
{
float sign = signf(factor);
@@ -297,8 +427,7 @@ static void sculpt_calc_blurred_cavity(SculptSession *ss,
factor_sum = sculpt_cavity_calc_factor(automasking, factor_sum);
- *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.cavity) = factor_sum;
- *(uchar *)SCULPT_vertex_attr_get(vertex, ss->attrs.stroke_id) = automasking->cavity_stroke_id;
+ *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_cavity) = factor_sum;
}
int SCULPT_automasking_settings_hash(Object *ob, AutomaskingCache *automasking)
@@ -331,6 +460,20 @@ int SCULPT_automasking_settings_hash(Object *ob, AutomaskingCache *automasking)
hash = BLI_hash_int_2d(hash, automasking->settings.initial_face_set);
}
+ if (automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL) {
+ hash = BLI_hash_int_2d(hash,
+ *reinterpret_cast<uint *>(&automasking->settings.view_normal_falloff));
+ hash = BLI_hash_int_2d(hash,
+ *reinterpret_cast<uint *>(&automasking->settings.view_normal_limit));
+ }
+
+ if (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL) {
+ hash = BLI_hash_int_2d(hash,
+ *reinterpret_cast<uint *>(&automasking->settings.start_normal_falloff));
+ hash = BLI_hash_int_2d(hash,
+ *reinterpret_cast<uint *>(&automasking->settings.start_normal_limit));
+ }
+
return hash;
}
@@ -338,13 +481,13 @@ static float sculpt_automasking_cavity_factor(AutomaskingCache *automasking,
SculptSession *ss,
PBVHVertRef vertex)
{
- uchar stroke_id = *(uchar *)SCULPT_vertex_attr_get(vertex, ss->attrs.stroke_id);
+ uchar stroke_id = *(uchar *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_stroke_id);
- if (stroke_id != automasking->cavity_stroke_id) {
+ if (stroke_id != automasking->current_stroke_id) {
sculpt_calc_blurred_cavity(ss, automasking, automasking->settings.cavity_blur_steps, vertex);
}
- float factor = *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.cavity);
+ float factor = *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_cavity);
bool inverted = automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_INVERTED;
if ((automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) &&
@@ -359,7 +502,8 @@ static float sculpt_automasking_cavity_factor(AutomaskingCache *automasking,
float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
SculptSession *ss,
- PBVHVertRef vert)
+ PBVHVertRef vert,
+ AutomaskingNodeData *automask_data)
{
if (!automasking) {
return 1.0f;
@@ -378,6 +522,18 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
return factor;
}
+ uchar stroke_id = ss->attrs.automasking_stroke_id ?
+ *(uchar *)(SCULPT_vertex_attr_get(vert, ss->attrs.automasking_stroke_id)) :
+ -1;
+
+ bool do_occlusion = (automasking->settings.flags &
+ (BRUSH_AUTOMASKING_VIEW_OCCLUSION | BRUSH_AUTOMASKING_VIEW_NORMAL)) ==
+ (BRUSH_AUTOMASKING_VIEW_OCCLUSION | BRUSH_AUTOMASKING_VIEW_NORMAL);
+ if (do_occlusion &&
+ automasking_view_occlusion_factor(automasking, ss, vert, stroke_id, automask_data)) {
+ return automasking_factor_end(ss, automasking, vert, 0.0f);
+ }
+
if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
if (!SCULPT_vertex_has_face_set(ss, vert, automasking->settings.initial_face_set)) {
return 0.0f;
@@ -396,11 +552,23 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
}
}
+ float mask = 1.0f;
+
+ if ((ss->cache || ss->filter_cache) &&
+ (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) {
+ mask *= automasking_brush_normal_factor(automasking, ss, vert, automask_data);
+ }
+
+ if ((ss->cache || ss->filter_cache) &&
+ (automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) {
+ mask *= automasking_view_normal_factor(automasking, ss, vert, automask_data);
+ }
+
if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
- return sculpt_automasking_cavity_factor(automasking, ss, vert);
+ mask *= sculpt_automasking_cavity_factor(automasking, ss, vert);
}
- return 1.0f;
+ return automasking_factor_end(ss, automasking, vert, mask);
}
void SCULPT_automasking_cache_free(AutomaskingCache *automasking)
@@ -582,6 +750,11 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski
automasking->settings.flags = sculpt_automasking_mode_effective_bits(sd, brush);
automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss);
+ automasking->settings.view_normal_limit = sd->automasking_view_normal_limit;
+ automasking->settings.view_normal_falloff = sd->automasking_view_normal_falloff;
+ automasking->settings.start_normal_limit = sd->automasking_start_normal_limit;
+ automasking->settings.start_normal_falloff = sd->automasking_start_normal_falloff;
+
if (brush && (brush->automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) {
automasking->settings.cavity_curve = brush->automasking_cavity_curve;
automasking->settings.cavity_factor = brush->automasking_cavity_factor;
@@ -594,7 +767,42 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski
}
}
-bool SCULPT_tool_can_reuse_cavity_mask(int sculpt_tool)
+static void sculpt_normal_occlusion_automasking_fill(AutomaskingCache *automasking,
+ Object *ob,
+ eAutomasking_flag mode)
+{
+ SculptSession *ss = ob->sculpt;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ /* No need to build original data since this is only called at the beginning of strokes.*/
+ AutomaskingNodeData nodedata;
+ nodedata.have_orig_data = false;
+
+ for (int i = 0; i < totvert; i++) {
+ PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
+
+ float f = *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor);
+
+ if ((int)mode & BRUSH_AUTOMASKING_BRUSH_NORMAL) {
+ f *= automasking_brush_normal_factor(automasking, ss, vertex, &nodedata);
+ }
+ if ((int)mode & BRUSH_AUTOMASKING_VIEW_NORMAL) {
+ if ((int)mode & BRUSH_AUTOMASKING_VIEW_OCCLUSION) {
+ f *= automasking_view_occlusion_factor(automasking, ss, vertex, -1, &nodedata);
+ }
+
+ f *= automasking_view_normal_factor(automasking, ss, vertex, &nodedata);
+ }
+
+ if (ss->attrs.automasking_stroke_id) {
+ *(uchar *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_stroke_id) = ss->stroke_id;
+ }
+
+ *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor) = f;
+ }
+}
+
+bool SCULPT_tool_can_reuse_automask(int sculpt_tool)
{
return ELEM(sculpt_tool,
SCULPT_TOOL_PAINT,
@@ -617,32 +825,61 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush);
SCULPT_boundary_info_ensure(ob);
- if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_CAVITY_ALL)) {
+ automasking->current_stroke_id = ss->stroke_id;
+
+ bool use_stroke_id = false;
+ int mode = sculpt_automasking_mode_effective_bits(sd, brush);
+
+ if ((mode & BRUSH_AUTOMASKING_VIEW_OCCLUSION) && (mode & BRUSH_AUTOMASKING_VIEW_NORMAL)) {
+ use_stroke_id = true;
+
+ if (!ss->attrs.automasking_occlusion) {
+ SculptAttributeParams params = {0};
+ ss->attrs.automasking_occlusion = BKE_sculpt_attribute_ensure(
+ ob,
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT8,
+ SCULPT_ATTRIBUTE_NAME(automasking_occlusion),
+ &params);
+ }
+ }
+
+ if (mode & BRUSH_AUTOMASKING_CAVITY_ALL) {
+ use_stroke_id = true;
+
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_CAVITY_USE_CURVE)) {
BKE_curvemapping_init(brush->automasking_cavity_curve);
BKE_curvemapping_init(sd->automasking_cavity_curve);
}
- SCULPT_stroke_id_ensure(ob);
- automasking->cavity_stroke_id = ss->stroke_id;
-
- if (!ss->attrs.cavity) {
+ if (!ss->attrs.automasking_cavity) {
SculptAttributeParams params = {0};
- ss->attrs.cavity = BKE_sculpt_attribute_ensure(
- ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(cavity), &params);
+ ss->attrs.automasking_cavity = BKE_sculpt_attribute_ensure(
+ ob,
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ SCULPT_ATTRIBUTE_NAME(automasking_cavity),
+ &params);
}
- /* Can we reuse the previous stroke's cavity mask? */
- else if (brush && SCULPT_tool_can_reuse_cavity_mask(brush->sculpt_tool)) {
+ }
+
+ if (use_stroke_id) {
+ SCULPT_stroke_id_ensure(ob);
+
+ bool have_occlusion = (mode & BRUSH_AUTOMASKING_VIEW_OCCLUSION) &&
+ (mode & BRUSH_AUTOMASKING_VIEW_NORMAL);
+
+ if (brush && SCULPT_tool_can_reuse_automask(brush->sculpt_tool) && !have_occlusion) {
int hash = SCULPT_automasking_settings_hash(ob, automasking);
if (hash == ss->last_automasking_settings_hash) {
- automasking->cavity_stroke_id = ss->last_automasking_settings_hash;
- automasking->can_reuse_cavity = true;
+ automasking->current_stroke_id = ss->last_automask_stroke_id;
+ automasking->can_reuse_mask = true;
}
}
- if (!automasking->can_reuse_cavity) {
- ss->last_cavity_stroke_id = ss->stroke_id;
+ if (!automasking->can_reuse_mask) {
+ ss->last_automask_stroke_id = ss->stroke_id;
}
}
@@ -675,6 +912,14 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
sculpt_face_sets_automasking_init(sd, ob);
}
+ int normal_bits = sculpt_automasking_mode_effective_bits(sd, brush) &
+ (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL |
+ BRUSH_AUTOMASKING_VIEW_OCCLUSION);
+
+ if (normal_bits) {
+ sculpt_normal_occlusion_automasking_fill(automasking, ob, (eAutomasking_flag)normal_bits);
+ }
+
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_automasking_init(ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps);
@@ -690,5 +935,8 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
bool SCULPT_automasking_needs_original(const Sculpt *sd, const Brush *brush)
{
- return sculpt_automasking_mode_effective_bits(sd, brush) & BRUSH_AUTOMASKING_CAVITY_ALL;
+
+ return sculpt_automasking_mode_effective_bits(sd, brush) &
+ (BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_BRUSH_NORMAL |
+ BRUSH_AUTOMASKING_VIEW_NORMAL);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 005892b88a0..f6da40065e0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -681,12 +681,16 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
angle_factor = floorf(angle_factor * 10) / 10.0f;
}
const float angle = angle_factor * M_PI;
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
@@ -694,7 +698,8 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ const float automask = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
@@ -729,12 +734,16 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
@@ -742,7 +751,8 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ const float automask = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -773,6 +783,9 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
@@ -781,6 +794,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
@@ -788,7 +802,8 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ const float automask = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -819,12 +834,16 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].propagation_steps_num == -1) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
@@ -832,7 +851,8 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ const float automask = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -862,6 +882,9 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -876,6 +899,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!SCULPT_check_vertex_pivot_symmetry(
orig_data.co, boundary->initial_vertex_position, symm)) {
@@ -883,7 +907,8 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ const float automask = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position);
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
index 00ad77e48cf..f2f7eac072e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -302,10 +302,17 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
/* Offset vertex. */
const float fade = SCULPT_brush_strength_factor(ss,
brush,
@@ -315,7 +322,8 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -387,6 +395,10 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -405,6 +417,8 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -413,7 +427,8 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -485,6 +500,10 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -503,6 +522,8 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -511,7 +532,8 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -601,6 +623,10 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
/* Tilted plane (front part of the brush). */
plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -621,6 +647,8 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
sub_v3_v3v3(val, intr_tilt, vd.co);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -629,7 +657,8 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -764,6 +793,10 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -776,6 +809,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
sub_v3_v3v3(val, intr, vd.co);
if (SCULPT_plane_trim(ss->cache, brush, val)) {
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -784,7 +819,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -922,6 +958,10 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -933,6 +973,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
sub_v3_v3v3(val, intr, vd.co);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -941,7 +983,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -1041,6 +1084,10 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
continue;
@@ -1058,6 +1105,9 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
if (!SCULPT_plane_trim(ss->cache, brush, val)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
/* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
@@ -1067,7 +1117,8 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -1202,6 +1253,10 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
KelvinletParams params;
BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -1212,6 +1267,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
fade = 1.0f;
}
else {
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -1220,7 +1277,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
}
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1267,7 +1325,9 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
if (vd.mask) {
mul_v3_fl(disp, 1.0f - *vd.mask);
}
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex));
+ mul_v3_fl(
+ disp,
+ SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex, &automask_data));
copy_v3_v3(proxy[vd.i], disp);
}
@@ -1339,12 +1399,18 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
orig_data.co,
@@ -1353,7 +1419,8 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1412,6 +1479,10 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -1427,7 +1498,8 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@@ -1485,12 +1557,18 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -1499,7 +1577,8 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
const int vi = vd.index;
float *disp_factor;
@@ -1600,10 +1679,16 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -1612,7 +1697,8 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float val[3];
if (vd.fno) {
@@ -1668,10 +1754,16 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -1680,7 +1772,8 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1746,11 +1839,17 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
/* Offset vertex. */
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -1759,7 +1858,8 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float val1[3];
float val2[3];
@@ -1863,10 +1963,16 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
copy_v3_v3(x_object_space, stroke_xz[0]);
copy_v3_v3(z_object_space, stroke_xz[1]);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -1875,7 +1981,8 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float disp_center[3];
float x_disp[3];
float z_disp[3];
@@ -1977,12 +2084,18 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
orig_data.co,
@@ -1991,7 +2104,8 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
if (grab_silhouette) {
float silhouette_test_dir[3];
@@ -2055,6 +2169,9 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = ss->cache->bstrength;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2110,7 +2227,9 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
mul_v3_fl(final_disp, 1.0f - *vd.mask);
}
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex));
+ mul_v3_fl(
+ final_disp,
+ SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex, &automask_data));
copy_v3_v3(proxy[vd.i], final_disp);
@@ -2174,12 +2293,18 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
/* Offset vertex. */
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = SCULPT_brush_strength_factor(ss,
brush,
orig_data.co,
@@ -2188,7 +2313,8 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -2258,11 +2384,17 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = SCULPT_brush_strength_factor(ss,
brush,
orig_data.co,
@@ -2271,7 +2403,8 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float current_disp[3];
float current_disp_norm[3];
float final_disp[3] = {0.0f, 0.0f, 0.0f};
@@ -2415,11 +2548,17 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = SCULPT_brush_strength_factor(ss,
brush,
orig_data.co,
@@ -2428,7 +2567,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
if (vd.mvert) {
@@ -2491,11 +2631,17 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -2504,7 +2650,8 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float limit_co[3];
float disp[3];
@@ -2557,11 +2704,17 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -2570,7 +2723,8 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float current_disp[3];
float current_disp_norm[3];
@@ -2718,16 +2872,29 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
- 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) *
- ss->cache->pressure;
+ SCULPT_automasking_node_update(ss, &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) *
+ ss->cache->pressure;
float avg[3], val[3];
@@ -2797,13 +2964,26 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
- const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.vertex, thread_id);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ 0.0f,
+ vd.vertex,
+ thread_id,
+ &automask_data);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index b354e2cb182..2b365a661ee 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -504,6 +504,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
madd_v3_v3fl(gravity, ss->cache->gravity_direction, -data->sd->gravity_factor);
}
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, SCULPT_automasking_active_cache_get(ss), &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float force[3];
float sim_location[3];
@@ -544,7 +548,8 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float brush_disp[3];
@@ -765,6 +770,9 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
}
AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, SCULPT_automasking_active_cache_get(ss), &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
float sim_location[3];
@@ -788,7 +796,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor);
const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
- SCULPT_automasking_factor_get(automasking, ss, vd.vertex);
+ SCULPT_automasking_factor_get(automasking, ss, vd.vertex, &automask_data);
madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
@@ -821,6 +829,9 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
{
AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss);
+ AutomaskingNodeData automask_data = {0};
+
+ automask_data.have_orig_data = true;
for (int constraint_it = 0; constraint_it < CLOTH_SIMULATION_ITERATIONS; constraint_it++) {
for (int i = 0; i < cloth_sim->tot_length_constraints; i++) {
@@ -860,9 +871,11 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2);
const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, vertex1)) *
- SCULPT_automasking_factor_get(automasking, ss, vertex1);
+ SCULPT_automasking_factor_get(
+ automasking, ss, vertex1, &automask_data);
const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, vertex2)) *
- SCULPT_automasking_factor_get(automasking, ss, vertex2);
+ SCULPT_automasking_factor_get(
+ automasking, ss, vertex2, &automask_data);
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
@@ -1434,11 +1447,15 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
sculpt_gravity[2] = -1.0f;
}
mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, SCULPT_automasking_active_cache_get(ss), &automask_data, node);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float fade = vd.mask ? *vd.mask : 0.0f;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
+ fade *= SCULPT_automasking_factor_get(
+ ss->filter_cache->automasking, ss, vd.vertex, &automask_data);
fade = 1.0f - fade;
float force[3] = {0.0f, 0.0f, 0.0f};
float disp[3], temp[3], transform[3][3];
@@ -1581,7 +1598,8 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
SCULPT_undo_push_begin(ob, op);
- SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
+ SCULPT_filter_cache_init(
+ C, ob, sd, SCULPT_UNDO_COORDS, event->mval, RNA_float_get(op->ptr, "area_normal_radius"));
ss->filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
@@ -1644,14 +1662,14 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* RNA. */
+ SCULPT_mesh_filter_properties(ot);
+
RNA_def_enum(ot->srna,
"type",
prop_cloth_filter_type,
CLOTH_FILTER_GRAVITY,
"Filter Type",
"Operation that is going to be applied to the mesh");
- RNA_def_float(
- ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
RNA_def_enum_flag(ot->srna,
"force_axis",
prop_cloth_filter_force_axis_items,
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
index 3f65248bc78..be52aaf0aa7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
@@ -129,6 +129,9 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
@@ -154,7 +157,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
if (fade > 0.05f) {
ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set;
@@ -173,7 +177,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
if (fade > 0.05f) {
SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
@@ -205,6 +210,9 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
}
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -222,7 +230,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
if (vd.mvert) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 6d1fad1fc65..42ea02caff8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -95,6 +95,10 @@ static void color_filter_task_cb(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->filter_cache->automasking, &automask_data, data->nodes[n]);
+
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -104,7 +108,8 @@ static void color_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
+ fade *= SCULPT_automasking_factor_get(
+ ss->filter_cache->automasking, ss, vd.vertex, &automask_data);
if (fade == 0.0f) {
continue;
}
@@ -290,6 +295,8 @@ static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
+ SCULPT_stroke_id_next(ob);
+
const float len = event->prev_press_xy[0] - event->xy[0];
filter_strength = filter_strength * -len * 0.001f;
@@ -361,7 +368,8 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
- SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COLOR);
+ SCULPT_filter_cache_init(
+ C, ob, sd, SCULPT_UNDO_COLOR, event->mval, RNA_float_get(op->ptr, "area_normal_radius"));
FilterCache *filter_cache = ss->filter_cache;
filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
@@ -386,9 +394,9 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
+ SCULPT_mesh_filter_properties(ot);
+
RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter Type", "");
- RNA_def_float(
- ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
PropertyRNA *prop = RNA_def_float_color(
ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "", 0.0f, 1.0f);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 0b68a527b59..4e481da03bc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -101,7 +101,12 @@ static void filter_cache_init_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(data->ob, node, data->filter_undo_type);
}
-void SCULPT_filter_cache_init(bContext *C, Object *ob, Sculpt *sd, const int undo_type)
+void SCULPT_filter_cache_init(bContext *C,
+ Object *ob,
+ Sculpt *sd,
+ const int undo_type,
+ const int mval[2],
+ float area_normal_radius)
{
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
@@ -159,6 +164,79 @@ void SCULPT_filter_cache_init(bContext *C, Object *ob, Sculpt *sd, const int und
ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_m4_m4(ss->filter_cache->viewmat, vc.rv3d->viewmat);
copy_m4_m4(ss->filter_cache->viewmat_inv, vc.rv3d->viewinv);
+
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+
+ float co[3];
+ float mval_fl[2] = {(float)mval[0], (float)mval[1]};
+
+ if (SCULPT_stroke_get_location(C, co, mval_fl, false)) {
+ PBVHNode **nodes;
+ int totnode;
+
+ /* Get radius from brush. */
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float radius;
+
+ if (brush) {
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ radius = paint_calc_object_space_radius(
+ &vc, co, (float)BKE_brush_size_get(scene, brush) * area_normal_radius);
+ }
+ else {
+ radius = BKE_brush_unprojected_radius_get(scene, brush) * area_normal_radius;
+ }
+ }
+ else {
+ radius = paint_calc_object_space_radius(&vc, co, (float)ups->size * area_normal_radius);
+ }
+
+ SculptSearchSphereData search_data = {
+ .original = true,
+ .center = co,
+ .radius_squared = radius * radius,
+ .ignore_fully_ineffective = true,
+ };
+
+ BKE_pbvh_search_gather(pbvh, SCULPT_search_sphere_cb, &search_data, &nodes, &totnode);
+
+ if (SCULPT_pbvh_calc_area_normal(
+ brush, ob, nodes, totnode, true, ss->filter_cache->initial_normal)) {
+ copy_v3_v3(ss->last_normal, ss->filter_cache->initial_normal);
+ }
+ else {
+ copy_v3_v3(ss->filter_cache->initial_normal, ss->last_normal);
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ /* Update last stroke location */
+
+ mul_m4_v3(ob->obmat, co);
+
+ add_v3_v3(ups->average_stroke_accum, co);
+ ups->average_stroke_counter++;
+ ups->last_stroke_valid = true;
+ }
+ else {
+ /* Use last normal. */
+ copy_v3_v3(ss->filter_cache->initial_normal, ss->last_normal);
+ }
+
+ /* Update view normal */
+ float projection_mat[4][4];
+ float mat[3][3];
+ float viewDir[3] = {0.0f, 0.0f, 1.0f};
+
+ ED_view3d_ob_project_mat_get(vc.rv3d, ob, projection_mat);
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_m3_m4(mat, vc.rv3d->viewinv);
+ mul_m3_v3(mat, viewDir);
+ copy_m3_m4(mat, ob->imat);
+ mul_m3_v3(mat, viewDir);
+ normalize_v3_v3(ss->filter_cache->view_normal, viewDir);
}
void SCULPT_filter_cache_free(SculptSession *ss)
@@ -288,15 +366,20 @@ static void mesh_filter_task_cb(void *__restrict userdata,
/* This produces better results as the relax operation is no completely focused on the
* boundaries. */
const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(data->ob, ss, ss->filter_cache->automasking, &automask_data, node);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
+ fade *= SCULPT_automasking_factor_get(
+ ss->filter_cache->automasking, ss, vd.vertex, &automask_data);
if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) {
/* Surface Smooth can't skip the loop for this vertex as it needs to calculate its
@@ -580,11 +663,18 @@ static void mesh_filter_surface_smooth_displace_task_cb(
PBVHNode *node = data->nodes[i];
PBVHVertexIter vd;
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->filter_cache->automasking, &automask_data, data->nodes[i]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
+ fade *= SCULPT_automasking_factor_get(
+ ss->filter_cache->automasking, ss, vd.vertex, &automask_data);
if (fade == 0.0f) {
continue;
}
@@ -622,6 +712,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
const float len = event->prev_press_xy[0] - event->xy[0];
filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+ SCULPT_stroke_id_next(ob);
SCULPT_vertex_random_access_ensure(ss);
bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type);
@@ -699,7 +790,8 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
SCULPT_undo_push_begin(ob, op);
- SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
+ SCULPT_filter_cache_init(
+ C, ob, sd, SCULPT_UNDO_COORDS, event->mval, RNA_float_get(op->ptr, "area_normal_radius"));
FilterCache *filter_cache = ss->filter_cache;
filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
@@ -746,6 +838,22 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
+void SCULPT_mesh_filter_properties(struct wmOperatorType *ot)
+{
+ RNA_def_float(
+ ot->srna,
+ "area_normal_radius",
+ 0.25,
+ 0.001,
+ 5.0,
+ "Normal Radius",
+ "Radius used for calculating area normal on initial click,\nin percentage of brush radius.",
+ 0.01,
+ 1.0);
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
+}
+
void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
{
/* Identifiers. */
@@ -761,14 +869,14 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* RNA. */
+ SCULPT_mesh_filter_properties(ot);
+
RNA_def_enum(ot->srna,
"type",
prop_mesh_filter_types,
MESH_FILTER_INFLATE,
"Filter Type",
"Operation that is going to be applied to the mesh");
- RNA_def_float(
- ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
RNA_def_enum_flag(ot->srna,
"deform_axis",
prop_mesh_filter_deform_axis_items,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index a28c18359e5..4817591a5c3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -27,6 +27,7 @@ extern "C" {
#endif
struct AutomaskingCache;
+struct AutomaskingNodeData;
struct Image;
struct ImageUser;
struct KeyBlock;
@@ -394,16 +395,20 @@ typedef struct AutomaskingSettings {
/* Flags from eAutomasking_flag. */
int flags;
int initial_face_set;
+
float cavity_factor;
int cavity_blur_steps;
struct CurveMapping *cavity_curve;
+
+ float start_normal_limit, start_normal_falloff;
+ float view_normal_limit, view_normal_falloff;
} AutomaskingSettings;
typedef struct AutomaskingCache {
AutomaskingSettings settings;
- bool can_reuse_cavity;
- uchar cavity_stroke_id;
+ bool can_reuse_mask;
+ uchar current_stroke_id;
} AutomaskingCache;
typedef struct FilterCache {
@@ -463,6 +468,8 @@ typedef struct FilterCache {
/* Auto-masking. */
AutomaskingCache *automasking;
+ float initial_normal[3];
+ float view_normal[3];
/* Pre-smoothed colors used by sharpening. Colors are HSL. */
float (*pre_smoothed_color)[4];
@@ -913,6 +920,8 @@ float SCULPT_vertex_mask_get(struct SculptSession *ss, PBVHVertRef vertex);
void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]);
void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]);
+bool SCULPT_vertex_is_occluded(SculptSession *ss, PBVHVertRef vertex, bool original);
+
/** Returns true if a color attribute exists in the current sculpt session. */
bool SCULPT_has_colors(const SculptSession *ss);
@@ -1194,7 +1203,8 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const float fno[3],
float mask,
const PBVHVertRef vertex,
- int thread_id);
+ int thread_id,
+ struct AutomaskingNodeData *automask_data);
/**
* Tilts a normal by the x and y tilt values using the view axis.
@@ -1282,9 +1292,30 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
/** \name Auto-masking.
* \{ */
+typedef struct AutomaskingNodeData {
+ PBVHNode *node;
+ SculptOrigVertData orig_data;
+ bool have_orig_data;
+} AutomaskingNodeData;
+
+/** Call before PBVH vertex iteration.
+ * \param automask_data: pointer to an uninitialized AutomaskingNodeData struct.
+ */
+void SCULPT_automasking_node_begin(struct Object *ob,
+ const SculptSession *ss,
+ struct AutomaskingCache *automasking,
+ AutomaskingNodeData *automask_data,
+ PBVHNode *node);
+
+/* Call before SCULPT_automasking_factor_get and SCULPT_brush_strength_factor. */
+void SCULPT_automasking_node_update(SculptSession *ss,
+ AutomaskingNodeData *automask_data,
+ PBVHVertexIter *vd);
+
float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
SculptSession *ss,
- PBVHVertRef vertex);
+ PBVHVertRef vertex,
+ AutomaskingNodeData *automask_data);
/* Returns the automasking cache depending on the active tool. Used for code that can run both for
* brushes and filter. */
@@ -1300,6 +1331,9 @@ float *SCULPT_boundary_automasking_init(Object *ob,
eBoundaryAutomaskMode mode,
int propagation_steps,
float *automask_factor);
+bool SCULPT_automasking_needs_normal(const SculptSession *ss,
+ const Sculpt *sculpt,
+ const Brush *brush);
bool SCULPT_automasking_needs_original(const struct Sculpt *sd, const struct Brush *brush);
int SCULPT_automasking_settings_hash(Object *ob, AutomaskingCache *automasking);
@@ -1329,8 +1363,14 @@ float *SCULPT_geodesic_from_vertex(Object *ob, PBVHVertRef vertex, float limit_r
/** \name Filter API
* \{ */
-void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, int undo_type);
+void SCULPT_filter_cache_init(struct bContext *C,
+ Object *ob,
+ Sculpt *sd,
+ int undo_type,
+ const int mval[2],
+ float area_normal_radius);
void SCULPT_filter_cache_free(SculptSession *ss);
+void SCULPT_mesh_filter_properties(struct wmOperatorType *ot);
void SCULPT_mask_filter_smooth_apply(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, int smooth_iterations);
@@ -1849,7 +1889,7 @@ BLI_INLINE bool SCULPT_tool_is_face_sets(int tool)
void SCULPT_stroke_id_ensure(struct Object *ob);
void SCULPT_stroke_id_next(struct Object *ob);
-bool SCULPT_tool_can_reuse_cavity_mask(int sculpt_tool);
+bool SCULPT_tool_can_reuse_automask(int sculpt_tool);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index 1e8731e54c0..9f57f9d6713 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -69,6 +69,10 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
test_radius *= brush->normal_radius_factor;
test.radius_squared = test_radius * test_radius;
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -78,6 +82,9 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
float normal[3];
copy_v3_v3(normal, vd.no ? vd.no : vd.fno);
mul_v3_m4v3(local_co, mat, vd.co);
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
/* Use the brush falloff to weight the sampled normals. */
const float fade = SCULPT_brush_strength_factor(ss,
brush,
@@ -87,7 +94,8 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
/* Sample the normal and area of the +X and -X axis individually. */
if (local_co[0] > 0.0f) {
@@ -144,6 +152,10 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -184,6 +196,9 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
if (!SCULPT_plane_trim(ss->cache, brush, val)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
/* 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;
@@ -195,7 +210,8 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
mul_v3_v3fl(proxy[vd.i], val, fade);
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index e56d967808f..64a55168977 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -1033,8 +1033,15 @@ static void sculpt_bake_cavity_exec_task_cb(void *__restrict userdata,
SCULPT_undo_push_node(tdata->ob, node, SCULPT_UNDO_MASK);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ tdata->ob, ss, ss->cache->automasking, &automask_data, node);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
- float automask = SCULPT_automasking_factor_get(tdata->automasking, ss, vd.vertex);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
+ float automask = SCULPT_automasking_factor_get(
+ tdata->automasking, ss, vd.vertex, &automask_data);
float mask;
switch (mode) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index e717c15d6dc..7946affdec5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -70,10 +70,17 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -82,7 +89,8 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float smooth_color[4];
SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
@@ -125,6 +133,10 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
IMB_colormanagement_srgb_to_scene_linear_v3(brush_color, brush_color);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
if (brush->flag & BRUSH_USE_GRADIENT) {
switch (brush->gradient_stroke_mode) {
case BRUSH_GRADIENT_PRESSURE:
@@ -161,6 +173,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -169,7 +183,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
/* Density. */
float noise = 1.0f;
@@ -197,7 +212,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
/* Final mix over the original color using brush alpha. We apply auto-making again
* at this point to avoid washing out non-binary masking modes like cavity masking. */
- float automasking = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ float automasking = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha * automasking);
float col[4];
@@ -404,10 +420,17 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
sub_v3_v3v3(brush_delta, ss->cache->location, ss->cache->last_location);
}
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -416,7 +439,8 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float current_disp[3];
float current_disp_norm[3];
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index 8a3a3fe7adc..6dfb01cec20 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -153,7 +153,10 @@ template<typename ImageBuffer> class PaintingKernel {
init_brush_test();
}
- bool paint(const Triangles &triangles, const PackedPixelRow &pixel_row, ImBuf *image_buffer)
+ bool paint(const Triangles &triangles,
+ const PackedPixelRow &pixel_row,
+ ImBuf *image_buffer,
+ AutomaskingNodeData *automask_data)
{
image_accessor.set_image_position(image_buffer, pixel_row.start_image_coordinate);
const TrianglePaintInput triangle = triangles.get_paint_input(pixel_row.triangle_index);
@@ -171,6 +174,7 @@ template<typename ImageBuffer> class PaintingKernel {
const float3 normal(0.0f, 0.0f, 0.0f);
const float3 face_normal(0.0f, 0.0f, 0.0f);
const float mask = 0.0f;
+
const float falloff_strength = SCULPT_brush_strength_factor(
ss,
brush,
@@ -180,7 +184,8 @@ template<typename ImageBuffer> class PaintingKernel {
face_normal,
mask,
BKE_pbvh_make_vref(PBVH_REF_NONE),
- thread_id);
+ thread_id,
+ automask_data);
float4 paint_color = brush_color * falloff_strength * brush_strength;
float4 buffer_color;
blend_color_mix_float(buffer_color, color, paint_color);
@@ -321,6 +326,9 @@ static void do_paint_pixels(void *__restrict userdata,
PaintingKernel<ImageBufferFloat4> kernel_float4(ss, brush, thread_id, mvert);
PaintingKernel<ImageBufferByte4> kernel_byte4(ss, brush, thread_id, mvert);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
ImageUser image_user = *data->image_data.image_user;
bool pixels_updated = false;
for (UDIMTilePixels &tile_data : node_data.tiles) {
@@ -347,10 +355,12 @@ static void do_paint_pixels(void *__restrict userdata,
}
bool pixels_painted = false;
if (image_buffer->rect_float != nullptr) {
- pixels_painted = kernel_float4.paint(node_data.triangles, pixel_row, image_buffer);
+ pixels_painted = kernel_float4.paint(
+ node_data.triangles, pixel_row, image_buffer, &automask_data);
}
else {
- pixels_painted = kernel_byte4.paint(node_data.triangles, pixel_row, image_buffer);
+ pixels_painted = kernel_byte4.paint(
+ node_data.triangles, pixel_row, image_buffer, &automask_data);
}
if (pixels_painted) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index d1418c8dc35..fa33417faba 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -157,9 +157,13 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
float total_disp[3];
zero_v3(total_disp);
@@ -182,7 +186,8 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
/* Apply the vertex mask to the displacement. */
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
+ const float automask = SCULPT_automasking_factor_get(
+ ss->cache->automasking, ss, vd.vertex, &automask_data);
mul_v3_fl(disp, mask * automask);
/* Accumulate the displacement. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 2ef3c28ba0c..08a6c037608 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -217,11 +217,17 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -230,7 +236,8 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float disp[3];
madd_v3_v3v3fl(disp, vd.co, ss->cache->detail_directions[vd.index], fade);
@@ -300,11 +307,17 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(
ss,
brush,
@@ -314,7 +327,8 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
if (smooth_mask) {
float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask;
val *= fade * bstrength;
@@ -470,12 +484,18 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
const int thread_id = BLI_task_parallel_thread_id(tls);
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -484,7 +504,8 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
float disp[3];
SCULPT_surface_smooth_laplacian_step(
@@ -512,11 +533,17 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ AutomaskingNodeData automask_data;
+ SCULPT_automasking_node_begin(
+ data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ SCULPT_automasking_node_update(ss, &automask_data, &vd);
+
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@@ -525,7 +552,8 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
- thread_id);
+ thread_id,
+ &automask_data);
SCULPT_surface_smooth_displace_step(
ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index dfaa0bd4daa..f841cd14386 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -46,7 +46,7 @@
#include <math.h>
#include <stdlib.h>
-void ED_sculpt_init_transform(struct bContext *C, Object *ob, const char *undo_name)
+void ED_sculpt_init_transform(struct bContext *C, Object *ob, const int mval[2], const char *undo_name)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
@@ -66,7 +66,8 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob, const char *undo_n
ss->pivot_rot[3] = 1.0f;
SCULPT_vertex_random_access_ensure(ss);
- SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
+
+ SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS, mval, 5.0);
if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) {
ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL;
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
index 3792cfefe06..f4f2e2a1c6e 100644
--- a/source/blender/editors/transform/transform_convert_sculpt.c
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -87,7 +87,7 @@ static void createTransSculpt(bContext *C, TransInfo *t)
copy_m3_m4(td->axismtx, ob->obmat);
BLI_assert(!(t->options & CTX_PAINT_CURVE));
- ED_sculpt_init_transform(C, ob, t->undo_name);
+ ED_sculpt_init_transform(C, ob, t->mval, t->undo_name);
}
/** \} */
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index e0567151aa4..9b2dad915ed 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -338,6 +338,10 @@ typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_CAVITY_INVERTED = (1 << 5),
BRUSH_AUTOMASKING_CAVITY_ALL = (1 << 4) | (1 << 5),
BRUSH_AUTOMASKING_CAVITY_USE_CURVE = (1 << 6),
+ /* (1 << 7) - unused. */
+ BRUSH_AUTOMASKING_BRUSH_NORMAL = (1 << 8),
+ BRUSH_AUTOMASKING_VIEW_NORMAL = (1 << 9),
+ BRUSH_AUTOMASKING_VIEW_OCCLUSION = (1 << 10),
} eAutomasking_flag;
typedef enum ePaintBrush_flag {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index cf163ab7019..80b1049ca23 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1025,6 +1025,9 @@ typedef struct Sculpt {
float automasking_cavity_factor;
char _pad[4];
+ float automasking_start_normal_limit, automasking_start_normal_falloff;
+ float automasking_view_normal_limit, automasking_view_normal_falloff;
+
struct CurveMapping *automasking_cavity_curve;
struct CurveMapping *automasking_cavity_curve_op; /* For use by operators */
struct Object *gravity_object;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 3f4542a0f64..f927a3dab89 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -3270,6 +3270,28 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_automasking_start_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BRUSH_NORMAL);
+ RNA_def_property_ui_text(prop,
+ "Area Normal",
+ "Affect only vertices with a similar normal to where the stroke starts");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_automasking_view_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_NORMAL);
+ RNA_def_property_ui_text(prop,
+ "View Normal",
+ "Affect only vertices with a normal that faces the viewer");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_automasking_view_occlusion", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_OCCLUSION);
+ RNA_def_property_ui_text(prop, "Occlusion", "Only affect vertices that are not occluded by other faces. (Slower performance)");
+ 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);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 60f2b289af0..5348cf80d22 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -953,7 +953,64 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cavity Curve", "Curve used for the sensitivity");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_start_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BRUSH_NORMAL);
+ RNA_def_property_ui_text(prop,
+ "Area Normal",
+ "Affect only vertices with a similar normal to where the stroke starts");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_view_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_NORMAL);
+ RNA_def_property_ui_text(prop,
+ "View Normal",
+ "Affect only vertices with a normal that faces the viewer");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_view_occlusion", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_OCCLUSION);
+ RNA_def_property_ui_text(prop, "Occlusion", "Only affect vertices that are not occluded by other faces. (Slower performance)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "automasking_start_normal_limit", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(
+ prop, NULL, "automasking_start_normal_limit");
+ RNA_def_property_range(prop, 0.0001f, M_PI);
+ RNA_def_property_ui_text(prop,
+ "Area Normal Limit",
+ "The range of angles that will be affected");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "automasking_start_normal_falloff", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(
+ prop, NULL, "automasking_start_normal_falloff");
+ RNA_def_property_range(prop, 0.0001f, 1.0f);
+ RNA_def_property_ui_text(prop,
+ "Area Normal Falloff",
+ "Extend the angular range with a falloff gradient");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "automasking_view_normal_limit", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(
+ prop, NULL, "automasking_view_normal_limit");
+ RNA_def_property_range(prop, 0.0001f, M_PI);
+ RNA_def_property_ui_text(prop,
+ "View Normal Limit",
+ "The range of angles that will be affected");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "automasking_view_normal_falloff", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(
+ prop, NULL, "automasking_view_normal_falloff");
+ RNA_def_property_range(prop, 0.0001f, 1.0f);
+ RNA_def_property_ui_text(prop,
+ "View Normal Falloff",
+ "Extend the angular range with a falloff gradient");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_symmetrize_direction_items);
RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator");