diff options
author | Pablo Dobarro <pablodp606@gmail.com> | 2020-03-26 18:46:32 +0300 |
---|---|---|
committer | Pablo Dobarro <pablodp606@gmail.com> | 2020-03-27 19:55:00 +0300 |
commit | 015c084bda936915980f662ba3f73c996f451f24 (patch) | |
tree | 8870473b2f5eccee47f7f599817c6a322632476e /source | |
parent | 7eacda5a2bedbefab208ac32b0556307a9ca758b (diff) |
Sculpt: Weight normal and area sampling towards the brush center
Previously, all vertices inside the brush radius were taken into account
equally when calculating the sculpt normal and area. This was causing
artifacts and unpredictable results with large brushes or meshes with
curvatures, as the strongest deformation point of all brushes is usually
in the center. By weighting the vertex normal and position towards the
center when sampling, all brushes should now behave in a more
predictable way in non-uniform surfaces.
Reviewed By: jbakker
Differential Revision: https://developer.blender.org/D6989
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 65 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 1 |
2 files changed, 53 insertions, 13 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 7db792d43ce..fe4aa971b55 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1301,6 +1301,8 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test) test->radius_squared = ss->cache ? ss->cache->radius_squared : ss->cursor_radius * ss->cursor_radius; + test->radius = sqrtf(test->radius_squared); + if (ss->cache) { copy_v3_v3(test->location, ss->cache->location); test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass; @@ -1866,6 +1868,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) { test_radius *= data->brush->normal_radius_factor; } + normal_test.radius = test_radius; normal_test.radius_squared = test_radius * test_radius; } @@ -1886,6 +1889,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, test_radius *= data->brush->normal_radius_factor; } } + area_test.radius = test_radius; area_test.radius_squared = test_radius * test_radius; } @@ -1919,10 +1923,26 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f); if (use_area_cos && area_test_r) { + /* Weight the coordinates towards the center. */ + float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius); + float afactor = 3.0f * p * p - 2.0f * p * p * p; + CLAMP(afactor, 0.0f, 1.0f); + + float disp[3]; + sub_v3_v3v3(disp, co, area_test.location); + mul_v3_fl(disp, 1.0f - afactor); + add_v3_v3v3(co, area_test.location, disp); add_v3_v3(anctd->area_cos[flip_index], co); + anctd->count_co[flip_index] += 1; } if (use_area_nos && normal_test_r) { + /* Weight the normals towards the center. */ + float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius); + float nfactor = 3.0f * p * p - 2.0f * p * p * p; + CLAMP(nfactor, 0.0f, 1.0f); + mul_v3_fl(no, nfactor); + add_v3_v3(anctd->area_nos[flip_index], no); anctd->count_no[flip_index] += 1; } @@ -1932,54 +1952,73 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, else { BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - const float *co; + float co[3]; + /* For bm_vert only. */ - const short *no_s; + short no_s[3]; if (use_original) { if (unode->bm_entry) { - BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s); + const float *temp_co; + const short *temp_no_s; + BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s); + copy_v3_v3(co, temp_co); + copy_v3_v3_short(no_s, temp_no_s); } else { - co = unode->co[vd.i]; - no_s = unode->no[vd.i]; + copy_v3_v3(co, unode->co[vd.i]); + copy_v3_v3_short(no_s, unode->no[vd.i]); } } else { - co = vd.co; + copy_v3_v3(co, vd.co); } normal_test_r = sculpt_brush_normal_test_sq_fn(&normal_test, co); area_test_r = sculpt_brush_area_test_sq_fn(&area_test, co); if (normal_test_r || area_test_r) { - float no_buf[3]; - const float *no; + float no[3]; int flip_index; data->any_vertex_sampled = true; if (use_original) { - normal_short_to_float_v3(no_buf, no_s); - no = no_buf; + normal_short_to_float_v3(no, no_s); } else { if (vd.no) { - normal_short_to_float_v3(no_buf, vd.no); - no = no_buf; + normal_short_to_float_v3(no, vd.no); } else { - no = vd.fno; + copy_v3_v3(no, vd.fno); } } flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <= 0.0f); + if (use_area_cos && area_test_r) { + /* Weight the coordinates towards the center. */ + float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius); + float afactor = 3.0f * p * p - 2.0f * p * p * p; + CLAMP(afactor, 0.0f, 1.0f); + + float disp[3]; + sub_v3_v3v3(disp, co, area_test.location); + mul_v3_fl(disp, 1.0f - afactor); + add_v3_v3v3(co, area_test.location, disp); + add_v3_v3(anctd->area_cos[flip_index], co); anctd->count_co[flip_index] += 1; } if (use_area_nos && normal_test_r) { + /* Weight the normals towards the center. */ + float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius); + float nfactor = 3.0f * p * p - 2.0f * p * p * p; + CLAMP(nfactor, 0.0f, 1.0f); + mul_v3_fl(no, nfactor); + add_v3_v3(anctd->area_nos[flip_index], no); anctd->count_no[flip_index] += 1; } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 1c22b4e40c1..7f93355e269 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -441,6 +441,7 @@ typedef struct SculptThreadedTaskData { /*************** Brush testing declarations ****************/ typedef struct SculptBrushTest { float radius_squared; + float radius; float location[3]; float dist; int mirror_symmetry_pass; |