Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Dobarro <pablodp606@gmail.com>2020-04-05 03:00:50 +0300
committerPablo Dobarro <pablodp606@gmail.com>2020-04-14 22:00:14 +0300
commit7dd8c889f18e9df5c86356fedb063e5ff9261577 (patch)
treed9e510368ade84a75a2013f54379ac2a464c577b /source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
parentf881ff129f785ed9491be04bc3dad6645903ddaa (diff)
Sculpt: Sharpen Mesh Filter
This mesh filter sharpens and smooths the mesh based on its curvature, resulting in pinching hard edges and polishing flat surfaces. It fixes most of the artifacts of the voxel remesher and those produced when sculpting hard surfaces and stylized models with creasing and flattening brushes. It needs and accumulate_displacement step before each filter iteration which can't be multithreaded in an easy way (it would need something to sync the threads when modifying the data of neighbors in a different node), but this does not affect performance in a significant way. Reviewed By: brecht Differential Revision: https://developer.blender.org/D7335
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_filter_mesh.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c95
1 files changed, 91 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);
}