From 5f63344e849ea6435bfd2de5584389cd18b22aa6 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Wed, 20 May 2020 21:11:35 +0200 Subject: Fix PBVH API returning wrong normal when using shape keys and modifiers The implementation of this function should match the one in SCULPT_vertex_co_get. This does not solve the issue when sculpting with modifiers active but I think this code is wrong Reviewed By: sergey, brecht Differential Revision: https://developer.blender.org/D7805 --- source/blender/editors/sculpt_paint/sculpt.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'source/blender/editors/sculpt_paint') diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index d2dda1be1e7..8443608cfa5 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -156,9 +156,16 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index) void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) { switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: - normal_short_to_float_v3(no, ss->mvert[index].no); - return; + case PBVH_FACES: { + if (ss->shapekey_active || ss->deform_modifiers_active) { + const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); + normal_short_to_float_v3(no, mverts[index].no); + } + else { + normal_short_to_float_v3(no, ss->mvert[index].no); + } + break; + } case PBVH_BMESH: copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); break; -- cgit v1.2.3 From 9b0f65c4a64120efca61450bad0556a653c36feb Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Mon, 18 May 2020 15:35:14 +0200 Subject: Fix naming in the PBVH neighbor iterator macro The only possible name for the iterator was ni, this should fix that. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7774 --- source/blender/editors/sculpt_paint/sculpt_intern.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/editors/sculpt_paint') diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index bc7a78f491c..191a6fdd62e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -120,7 +120,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ neighbor_iterator.i++) { \ - neighbor_iterator.index = ni.neighbors[ni.i]; + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; /* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come * first since they are nearest for floodfill. */ @@ -128,8 +128,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ neighbor_iterator.i--) { \ - neighbor_iterator.index = ni.neighbors[ni.i]; \ - neighbor_iterator.is_duplicate = (ni.i >= \ + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ neighbor_iterator.size - neighbor_iterator.num_duplicates); #define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \ -- cgit v1.2.3 From 9aea7dc7c65b94aff0dda299c7269a252bf04b05 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Wed, 20 May 2020 01:41:47 +0200 Subject: Fix Pose Brush origin position with large brush size When the brush size is bigger than the entire mesh, fdata.tot_co can be 0, so the pose origin will default to (0,0,0), which does not make much sense. After this patch, the pose origin will be set to the farthest vertex from the pose origin, which at least should be in the surface of the mesh and in most cases in the direction the pose brush was already detecting the origin. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7773 --- source/blender/editors/sculpt_paint/sculpt_pose.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'source/blender/editors/sculpt_paint') diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index fde4a9d1d23..8ef059183e3 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -367,6 +367,10 @@ typedef struct PoseFloodFillData { bool is_first_iteration; + /* In topology mode this stores the furthest point from the stroke origin for cases when a pose + * origin based on the brush radius can't be set. */ + float fallback_floodfill_origin[3]; + /* Fallback origin. If we can't find any face set to continue, use the position of all vertices * that have the current face set. */ float fallback_origin[3]; @@ -377,12 +381,17 @@ static bool pose_topology_floodfill_cb( SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; + const float *co = SCULPT_vertex_co_get(ss, to_v); if (data->pose_factor) { data->pose_factor[to_v] = 1.0f; } - const float *co = SCULPT_vertex_co_get(ss, to_v); + if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) < + len_squared_v3v3(data->pose_initial_co, co)) { + copy_v3_v3(data->fallback_floodfill_origin, co); + } + if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { return true; @@ -521,12 +530,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd, }; zero_v3(fdata.pose_origin); copy_v3_v3(fdata.pose_initial_co, initial_location); + copy_v3_v3(fdata.fallback_floodfill_origin, initial_location); SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata); SCULPT_floodfill_free(&flood); if (fdata.tot_co > 0) { mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co); } + else { + copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin); + } /* Offset the pose origin. */ float pose_d[3]; -- cgit v1.2.3 From 18f33f293bfe08e87c50cad4a9d628592d7a3d15 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Tue, 19 May 2020 00:00:21 +0200 Subject: Fix Cloth Brush grab deformation mode The grab mode was not correctly implemented, so the way it was working was confusing for users. - Grab delta was calculated in increments from the last stroke position, so it did not match the behavior of a grab brush. I refactored the grab delta calculation to make this change more explicit. - Grab displacement was not calculated from the original coordinates - Grab was using an incorrect strength Grab is now setting the position of the affected vertices directly and the constraints solve the rest of the cloth. I also tried to implement an alternative version based on applying forces to move the vertices to the grab position, but I think this is more controllable and the grab falloff can be adjusted by tweaking the simulation falloff. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7756 --- source/blender/editors/sculpt_paint/paint_stroke.c | 3 +- source/blender/editors/sculpt_paint/sculpt.c | 101 ++++++++++++--------- source/blender/editors/sculpt_paint/sculpt_cloth.c | 29 +++++- .../blender/editors/sculpt_paint/sculpt_intern.h | 7 ++ 4 files changed, 90 insertions(+), 50 deletions(-) (limited to 'source/blender/editors/sculpt_paint') diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 7887aaaf658..463334720c5 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -230,8 +230,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode) SCULPT_TOOL_THUMB)) { return false; } - else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { + else if (SCULPT_is_cloth_deform_brush(brush)) { return false; } else { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 8443608cfa5..c42170695c2 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -2091,9 +2091,13 @@ static float brush_strength(const Sculpt *sd, case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; case SCULPT_TOOL_CLOTH: - /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over - * the same vertices. */ - if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) { + if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { + /* Grab deform uses the same falloff as a regular grab brush. */ + return root_alpha * feather; + } + else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) { + /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over + * the same vertices. */ return 0.1f * alpha * flip * pressure * overlap * feather; } else { @@ -6199,6 +6203,34 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo } } +/* In these brushes the grab delta is calculated always from the initial stroke location, which is + * generally used to create grab deformations. */ +static bool sculpt_needs_delta_from_anchored_origin(Brush *brush) +{ + return ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_POSE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_ELASTIC_DEFORM) || + SCULPT_is_cloth_deform_brush(brush); +} + +/* In these brushes the grab delta is calculated from the previous stroke location, which is used + * to calculate to orientate the brush tip and deformation towards the stroke direction. */ +static bool sculpt_needs_delta_for_tip_orientation(Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { + return !SCULPT_is_cloth_deform_brush(brush); + } + return ELEM(brush->sculpt_tool, + SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_PINCH, + SCULPT_TOOL_MULTIPLANE_SCRAPE, + SCULPT_TOOL_CLAY_THUMB, + SCULPT_TOOL_NUDGE, + SCULPT_TOOL_SNAKE_HOOK); +} + static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush) { SculptSession *ss = ob->sculpt; @@ -6242,38 +6274,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* Compute delta to move verts by. */ if (!cache->first_time) { - switch (tool) { - case SCULPT_TOOL_GRAB: - case SCULPT_TOOL_POSE: - case SCULPT_TOOL_THUMB: - case SCULPT_TOOL_ELASTIC_DEFORM: - sub_v3_v3v3(delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ob->obmat); - mul_mat3_m4_v3(imat, delta); - add_v3_v3(cache->grab_delta, delta); - break; - case SCULPT_TOOL_CLAY_STRIPS: - case SCULPT_TOOL_PINCH: - case SCULPT_TOOL_CLOTH: - case SCULPT_TOOL_MULTIPLANE_SCRAPE: - case SCULPT_TOOL_CLAY_THUMB: - case SCULPT_TOOL_NUDGE: - case SCULPT_TOOL_SNAKE_HOOK: - if (brush->flag & BRUSH_ANCHORED) { - float orig[3]; - mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); - sub_v3_v3v3(cache->grab_delta, grab_location, orig); - } - else { - sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - } - invert_m4_m4(imat, ob->obmat); - mul_mat3_m4_v3(imat, cache->grab_delta); - break; - default: - /* Use for 'Brush.topology_rake_factor'. */ + if (sculpt_needs_delta_from_anchored_origin(brush)) { + sub_v3_v3v3(delta, grab_location, cache->old_grab_location); + invert_m4_m4(imat, ob->obmat); + mul_mat3_m4_v3(imat, delta); + add_v3_v3(cache->grab_delta, delta); + } + else if (sculpt_needs_delta_for_tip_orientation(brush)) { + if (brush->flag & BRUSH_ANCHORED) { + float orig[3]; + mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); + sub_v3_v3v3(cache->grab_delta, grab_location, orig); + } + else { sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - break; + } + invert_m4_m4(imat, ob->obmat); + mul_mat3_m4_v3(imat, cache->grab_delta); + } + else { + /* Use for 'Brush.topology_rake_factor'. */ + sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); } } else { @@ -6294,18 +6315,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru copy_v3_v3(cache->anchored_location, cache->true_location); } } - else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) { + else if (tool == SCULPT_TOOL_ELASTIC_DEFORM || SCULPT_is_cloth_deform_brush(brush)) { copy_v3_v3(cache->anchored_location, cache->true_location); } else if (tool == SCULPT_TOOL_THUMB) { copy_v3_v3(cache->anchored_location, cache->orig_grab_location); } - if (ELEM(tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_POSE)) { + if (sculpt_needs_delta_from_anchored_origin(brush)) { /* Location stays the same for finding vertices in brush radius. */ copy_v3_v3(cache->true_location, cache->orig_grab_location); @@ -6376,9 +6393,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po if (cache->first_time || !((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) || - (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || - (brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) { + (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || SCULPT_is_cloth_deform_brush(brush))) { RNA_float_get_array(ptr, "location", cache->true_location); } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index b1cc6d02bbb..84d575c92d1 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -212,8 +212,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, const float *grab_delta = data->grab_delta; float(*imat)[4] = data->mat; - const bool use_falloff_plane = brush->cloth_force_falloff_type == - BRUSH_CLOTH_FORCE_FALLOFF_PLANE; + const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) && + brush->cloth_force_falloff_type == + BRUSH_CLOTH_FORCE_FALLOFF_PLANE; PBVHVertexIter vd; const float bstrength = ss->cache->bstrength; @@ -245,14 +246,29 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, gravity, ss->cache->gravity_direction, -ss->cache->radius * data->sd->gravity_factor); } + /* Original data for deform brushes. */ + SculptOrigVertData orig_data; + if (SCULPT_is_cloth_deform_brush(brush)) { + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + } + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float force[3]; const float sim_factor = cloth_brush_simulation_falloff_get( brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]); + float current_vertex_location[3]; + if (SCULPT_is_cloth_deform_brush(brush)) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + copy_v3_v3(current_vertex_location, orig_data.co); + } + else { + copy_v3_v3(current_vertex_location, vd.co); + } + /* When using the plane falloff mode the falloff is not constrained by the brush radius. */ - if (sculpt_brush_test_sq_fn(&test, vd.co) || use_falloff_plane) { + if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) { float dist = sqrtf(test.dist); @@ -263,7 +279,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, const float fade = sim_factor * bstrength * SCULPT_brush_strength_factor(ss, brush, - vd.co, + current_vertex_location, dist, vd.no, vd.fno, @@ -292,7 +308,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(force, offset, -fade); break; case BRUSH_CLOTH_DEFORM_GRAB: - mul_v3_v3fl(force, grab_delta, fade); + /* Grab writes the positions in the simulation directly without applying forces. */ + madd_v3_v3v3fl( + cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade); + zero_v3(force); break; case BRUSH_CLOTH_DEFORM_PINCH_POINT: if (use_falloff_plane) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 191a6fdd62e..ec7ea1d85f4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -333,6 +333,13 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, struct SculptSession *ss, const float outline_col[3], float outline_alpha); + +BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) +{ + return brush->sculpt_tool == SCULPT_TOOL_CLOTH && + brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB; +} + /* Pose Brush. */ void SCULPT_do_pose_brush(struct Sculpt *sd, struct Object *ob, -- cgit v1.2.3