Compare commits

...

35 Commits

Author SHA1 Message Date
1d440b10bf temp-sculpt-normals-masking: Fix warnings 2022-09-28 23:19:41 -07:00
5dff243cb1 Merge remote-tracking branch 'origin' into temp-sculpt-normals-masking 2022-09-28 23:08:48 -07:00
222c71ec4b temp-sculpt-normals-masking: cleanup code a bit
Also, don't reuse automask stroke id if view normal
occlusion is on.
2022-09-28 22:53:52 -07:00
c63d6e3698 Merge branch 'master' into temp-sculpt-normals-masking 2022-09-28 17:19:29 -07:00
a84e67adaf temp-sculpt-normals-masking: Make requested patch changes 2022-09-27 10:46:57 -07:00
337d21b77d Merge branch 'master' into temp-sculpt-normals-masking 2022-09-27 09:28:27 -07:00
4a6b89d6eb Merge branch 'master' into temp-sculpt-normals-masking 2022-09-24 10:08:42 -07:00
be6b62d0cb temp-sculpt-normals-masking: Replace a few usages of float[3] with
float3
2022-09-23 15:26:37 -07:00
ac6469bf8a Merge branch 'master' into temp-sculpt-normals-masking 2022-09-23 15:20:04 -07:00
aeebf86606 temp-sculpt-normals-masking: Update some comments 2022-09-22 11:37:53 -07:00
f2363bbe92 Merge remote-tracking branch 'origin' into temp-sculpt-normals-masking 2022-09-22 11:29:53 -07:00
3f80385118 temp-sculpt-normals-masking: Use a stroke id attribute for occlusion
Use a stroke id temp attribute to keep track of which verts
need occlusion tests.
2022-09-22 11:28:16 -07:00
0f2e141b62 Merge branch 'master' into temp-sculpt-normals-masking 2022-09-20 11:49:39 -07:00
fedb6cdefd Merge branch 'master' into temp-sculpt-normals-masking 2022-08-29 12:02:49 -07:00
e255e5445c temp-sculpt-normals-masking: Remove unwanted formatting changes 2022-07-30 11:34:38 -07:00
6bfbdc4bff temp-sculpt-normals-masking: Make occlusion suboption of view normal 2022-07-30 11:31:06 -07:00
447425ad99 Merge branch 'master' into temp-sculpt-normals-masking 2022-07-30 11:18:40 -07:00
e1966d8cdc Merge remote-tracking branch 'origin' into temp-sculpt-normals-masking 2022-07-28 10:15:41 -07:00
7731690dba temp-sculpt-normals-masking: Implement new masking modes for factor cache 2022-07-26 15:09:05 -07:00
23638dd679 Merge branch 'master' into temp-sculpt-normals-masking 2022-07-26 14:39:55 -07:00
6e518ccfb3 Merge remote-tracking branch 'origin' into temp-sculpt-normals-masking 2022-07-26 14:22:33 -07:00
5a64ca2755 temp-sculpt-normals-masking: Undo pbvh leaf limit change 2022-07-25 13:52:02 -07:00
d779802563 temp-sculpt-normals-masking: Add occlusion mode 2022-07-25 13:50:55 -07:00
a472ced73b temp-sculpt-normals-masking: Support normals automasking for sculpt
filters

* Sculpt filters now sample the area normal on first click.
* Small cleanup: there is now a utility function for defining common
  filter operator properties, SCULPT_mesh_filter_properties.
* Filters now update the last location (used for e.g. view centering).
2022-07-16 15:08:18 -07:00
0286a6774e Merge remote-tracking branch 'origin' into temp-sculpt-normals-masking 2022-07-16 13:58:36 -07:00
f708287cc7 Merge remote-tracking branch 'origin' into temp-sculpt-normals-masking 2022-07-15 16:16:24 -07:00
9e77eb2614 temp-sculpt-normals-masking: fix crash 2022-07-11 03:41:56 -07:00
10e9098637 temp-sculpt-normals-masking: Give automasking access to original normals
* Automasking code now has access to original normals
* This works in a fairly clunky way that preserves the
  existing automasking API.  Alternative is to give up
  on reusing undo data for original co/normal in
  PBVH_FACES/PBVH_GRIDS and just use a temporary array
  or attribute for it.  That would allow vertex-level
  lookups independent of the pbvh nodes.
2022-07-11 03:31:28 -07:00
e8c5e182f3 Merge branch 'master' into temp-sculpt-normals-masking 2022-07-11 01:46:13 -07:00
0f49ac60a8 Merge branch 'master' into temp-sculpt-normals-masking 2022-07-07 10:28:55 -07:00
484337f4f7 temp-sculpt-normals-masking: Patch changes
* Changed name 'Occlusion' to 'View Normal'
* Changed name 'Initial Normal' to 'Area Normal'
* Added missing RNA for brush automasking.
* Added normals automasking modes to brush advanced panel.
2022-06-28 23:43:16 -07:00
322cf5be0c Merge branch 'master' into temp-sculpt-normals-masking 2022-06-28 22:44:21 -07:00
f82c53c583 Merge branch 'master' into temp-sculpt-normals-masking 2022-06-27 11:27:17 -07:00
e65d0a1ef7 temp-sculpt-normals-masking: Remove old code 2022-06-26 22:34:36 -07:00
097fb45a84 temp-sculpt-normals-masking: Occlusion and initial normal masking
Adds support for two normal masking modes: one that compares
with the view normal and another that compares with the
initial brush normal.  Both support falloffs.
2022-06-26 18:31:14 -07:00
27 changed files with 1050 additions and 130 deletions

View File

@@ -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()

View File

@@ -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):

View File

@@ -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")

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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);
}
}

View File

@@ -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,
}
}
if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) {
return sculpt_automasking_cavity_factor(automasking, ss, vert);
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);
}
return 1.0f;
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) {
mask *= sculpt_automasking_cavity_factor(automasking, ss, vert);
}
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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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];

View File

@@ -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) {

View File

@@ -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. */

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}
/** \} */

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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");