diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_filter_mesh.c | 95 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 5 |
2 files changed, 96 insertions, 4 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 7116ec77fa4..ac307df34fd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -128,6 +128,8 @@ void SCULPT_filter_cache_free(SculptSession *ss) MEM_SAFE_FREE(ss->filter_cache->prev_face_set); MEM_SAFE_FREE(ss->filter_cache->automask); MEM_SAFE_FREE(ss->filter_cache->surface_smooth_laplacian_disp); + MEM_SAFE_FREE(ss->filter_cache->sharpen_factor); + MEM_SAFE_FREE(ss->filter_cache->accum_disp); MEM_SAFE_FREE(ss->filter_cache); } @@ -140,6 +142,7 @@ typedef enum eSculptMeshFilterTypes { MESH_FILTER_RELAX = 5, MESH_FILTER_RELAX_FACE_SETS = 6, MESH_FILTER_SURFACE_SMOOTH = 7, + MESH_FILTER_SHARPEN = 8, } eSculptMeshFilterTypes; static EnumPropertyItem prop_mesh_filter_types[] = { @@ -159,6 +162,7 @@ static EnumPropertyItem prop_mesh_filter_types[] = { 0, "Surface Smooth", "Smooth the surface of the mesh, preserving the volume"}, + {MESH_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen", "Sharpen the cavities of the mesh"}, {0, NULL, 0, NULL, NULL}, }; @@ -181,7 +185,8 @@ static bool sculpt_mesh_filter_needs_pmap(int filter_type, bool use_face_sets) MESH_FILTER_SMOOTH, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS, - MESH_FILTER_SURFACE_SMOOTH); + MESH_FILTER_SURFACE_SMOOTH, + MESH_FILTER_SHARPEN); } static void mesh_filter_task_cb(void *__restrict userdata, @@ -324,6 +329,26 @@ static void mesh_filter_task_cb(void *__restrict userdata, ss->filter_cache->surface_smooth_shape_preservation); break; } + case MESH_FILTER_SHARPEN: { + const float smooth_ratio = ss->filter_cache->sharpen_smooth_ratio; + + /* This filter can't work at full strength as it needs multiple iterations to reach a + * stable state. */ + fade = clamp_f(fade, 0.0f, 0.5f); + + float disp_sharpen[3]; + copy_v3_v3(disp_sharpen, ss->filter_cache->accum_disp[vd.index]); + mul_v3_fl(disp_sharpen, 1.0f - ss->filter_cache->sharpen_factor[vd.index]); + + float disp_avg[3]; + float avg_co[3]; + SCULPT_neighbor_coords_average(ss, avg_co, vd.index); + sub_v3_v3v3(disp_avg, avg_co, vd.co); + mul_v3_v3fl( + disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index])); + add_v3_v3v3(disp, disp_avg, disp_sharpen); + break; + } } for (int it = 0; it < 3; it++) { @@ -332,7 +357,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, } } - if (filter_type == MESH_FILTER_SURFACE_SMOOTH) { + if (ELEM(filter_type, MESH_FILTER_SURFACE_SMOOTH, MESH_FILTER_SHARPEN)) { madd_v3_v3v3fl(final_pos, vd.co, disp, clamp_f(fade, 0.0f, 1.0f)); } else { @@ -348,6 +373,46 @@ static void mesh_filter_task_cb(void *__restrict userdata, BKE_pbvh_node_mark_update(node); } +static void mesh_filter_sharpen_init_factors(SculptSession *ss) +{ + const int totvert = SCULPT_vertex_count_get(ss); + for (int i = 0; i < totvert; i++) { + float avg[3]; + SCULPT_neighbor_coords_average(ss, avg, i); + ss->filter_cache->sharpen_factor[i] = len_v3v3(avg, SCULPT_vertex_co_get(ss, i)); + } + float max_factor = 0.0f; + for (int i = 0; i < totvert; i++) { + if (ss->filter_cache->sharpen_factor[i] > max_factor) { + max_factor = ss->filter_cache->sharpen_factor[i]; + } + } + + max_factor = 1.0f / max_factor; + for (int i = 0; i < totvert; i++) { + ss->filter_cache->sharpen_factor[i] *= max_factor; + ss->filter_cache->sharpen_factor[i] = 1.0f - pow2f(1.0f - ss->filter_cache->sharpen_factor[i]); + } +} + +static void mesh_filter_sharpen_accumulate_displacement(SculptSession *ss) +{ + const int totvert = SCULPT_vertex_count_get(ss); + for (int i = 0; i < totvert; i++) { + zero_v3(ss->filter_cache->accum_disp[i]); + } + for (int i = 0; i < totvert; i++) { + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + float disp_n[3]; + sub_v3_v3v3(disp_n, SCULPT_vertex_co_get(ss, i), SCULPT_vertex_co_get(ss, ni.index)); + mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[i]); + add_v3_v3(ss->filter_cache->accum_disp[ni.index], disp_n); + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + } +} + static void mesh_filter_surface_smooth_displace_task_cb( void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls)) { @@ -403,6 +468,10 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false); + if (filter_type == MESH_FILTER_SHARPEN) { + mesh_filter_sharpen_accumulate_displacement(ss); + } + SculptThreadedTaskData data = { .sd = sd, .ob = ob, @@ -470,6 +539,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false); + const int totvert = SCULPT_vertex_count_get(ss); if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) { return OPERATOR_CANCELLED; } @@ -487,14 +557,22 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent } if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SURFACE_SMOOTH) { - ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN( - 3 * sizeof(float) * SCULPT_vertex_count_get(ss), "surface smooth disp"); + ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN(3 * sizeof(float) * totvert, + "surface smooth disp"); ss->filter_cache->surface_smooth_shape_preservation = RNA_float_get( op->ptr, "surface_smooth_shape_preservation"); ss->filter_cache->surface_smooth_current_vertex = RNA_float_get( op->ptr, "surface_smooth_current_vertex"); } + if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SHARPEN) { + ss->filter_cache->sharpen_smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio"); + ss->filter_cache->sharpen_factor = MEM_mallocN(sizeof(float) * totvert, "sharpen factor"); + ss->filter_cache->accum_disp = MEM_mallocN(3 * sizeof(float) * totvert, "orco"); + + mesh_filter_sharpen_init_factors(ss); + } + ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X; ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y; ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z; @@ -568,4 +646,13 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot) "How much the position of each individual vertex influences the final result", 0.0f, 1.0f); + RNA_def_float(ot->srna, + "sharpen_smooth_ratio", + 0.35f, + 0.0f, + 1.0f, + "Smooth Ratio", + "How much smoothing is applied to polished surfaces", + 0.0f, + 1.0f); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index b379c1ab8af..8189ca8c551 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -818,6 +818,11 @@ typedef struct FilterCache { float surface_smooth_shape_preservation; float surface_smooth_current_vertex; + /* Sharpen mesh filter. */ + float sharpen_smooth_ratio; + float *sharpen_factor; + float (*accum_disp)[3]; + /* unmasked nodes */ PBVHNode **nodes; int totnode; |