Compare commits
35 Commits
refactor-m
...
temp-sculp
Author | SHA1 | Date | |
---|---|---|---|
1d440b10bf | |||
5dff243cb1 | |||
222c71ec4b | |||
c63d6e3698 | |||
a84e67adaf | |||
337d21b77d | |||
4a6b89d6eb | |||
be6b62d0cb | |||
ac6469bf8a | |||
aeebf86606 | |||
f2363bbe92 | |||
3f80385118 | |||
0f2e141b62 | |||
fedb6cdefd | |||
e255e5445c | |||
6bfbdc4bff | |||
447425ad99 | |||
e1966d8cdc | |||
7731690dba | |||
23638dd679 | |||
6e518ccfb3 | |||
5a64ca2755 | |||
d779802563 | |||
a472ced73b | |||
0286a6774e | |||
f708287cc7 | |||
9e77eb2614 | |||
10e9098637 | |||
e8c5e182f3 | |||
0f49ac60a8 | |||
484337f4f7 | |||
322cf5be0c | |||
f82c53c583 | |||
e65d0a1ef7 | |||
097fb45a84 |
@@ -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()
|
||||
|
||||
|
@@ -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):
|
||||
|
@@ -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")
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
@@ -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), ¶ms);
|
||||
ss->attrs.automasking_stroke_id = BKE_sculpt_attribute_ensure(
|
||||
ob,
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_INT8,
|
||||
SCULPT_ATTRIBUTE_NAME(automasking_stroke_id),
|
||||
¶ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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),
|
||||
¶ms);
|
||||
}
|
||||
}
|
||||
|
||||
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), ¶ms);
|
||||
ss->attrs.automasking_cavity = BKE_sculpt_attribute_ensure(
|
||||
ob,
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_FLOAT,
|
||||
SCULPT_ATTRIBUTE_NAME(automasking_cavity),
|
||||
¶ms);
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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(¶ms, 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);
|
||||
|
@@ -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,
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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];
|
||||
|
@@ -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) {
|
||||
|
@@ -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. */
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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");
|
||||
|
Reference in New Issue
Block a user