[Bf-blender-cvs] [a218be30803] master: Sculpt: Surface Smooth Brush and Mesh Filter

Pablo Dobarro noreply at git.blender.org
Thu Mar 26 16:15:27 CET 2020


Commit: a218be308032ac4c270950f450bc7a5e05f066ce
Author: Pablo Dobarro
Date:   Thu Mar 26 16:05:46 2020 +0100
Branches: master
https://developer.blender.org/rBa218be308032ac4c270950f450bc7a5e05f066ce

Sculpt: Surface Smooth Brush and Mesh Filter

This implements the Surface Smooth Brush as a mode inside the Smooth tool,
which uses the HC algorithm from "Improved Laplacian Smoothing of Noisy Surface Meshes".
Comparted to the regular smooth brush with laplacian smooth, this brush removes
the surface while preserving the volume of the object.
The smooth result can be controlled by tweaing the original shape preservation,
displacement and iteration count.
The same surface smooth operation is also available as a mesh filter.

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D7057

===================================================================

M	release/scripts/startup/bl_ui/properties_paint_common.py
M	release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
M	source/blender/blenkernel/intern/brush.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/makesdna/DNA_brush_types.h
M	source/blender/makesrna/intern/rna_brush.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 34afcc09407..3d2474d006a 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -665,6 +665,14 @@ def brush_settings(layout, context, brush, popover=False):
             col.prop(brush, "use_multiplane_scrape_dynamic")
             col.prop(brush, "show_multiplane_scrape_planes_preview")
 
+        if brush.sculpt_tool == 'SMOOTH':
+            col = layout.column()
+            col.prop(brush, "smooth_deform_type")
+            if brush.smooth_deform_type == 'SURFACE':
+                col.prop(brush, "surface_smooth_shape_preservation")
+                col.prop(brush, "surface_smooth_current_vertex")
+                col.prop(brush, "surface_smooth_iterations")
+
         if brush.sculpt_tool == 'MASK':
             layout.row().prop(brush, "mask_tool", expand=True)
 
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index c501c4f66a1..9a7e42bdbce 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1031,6 +1031,9 @@ class _defs_sculpt:
             layout.prop(props, "strength")
             layout.prop(props, "deform_axis")
             layout.prop(props, "use_face_sets")
+            if (props.type == "SURFACE_SMOOTH"):
+                layout.prop(props, "surface_smooth_shape_preservation", expand=False)
+                layout.prop(props, "surface_smooth_current_vertex", expand=False)
 
         return dict(
             idname="builtin.mesh_filter",
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index e6045c45dc8..2306b046026 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1348,6 +1348,9 @@ void BKE_brush_sculpt_reset(Brush *br)
       br->flag &= ~BRUSH_SPACE_ATTEN;
       br->spacing = 5;
       br->alpha = 0.7f;
+      br->surface_smooth_shape_preservation = 0.5f;
+      br->surface_smooth_current_vertex = 0.5f;
+      br->surface_smooth_iterations = 4;
       break;
     case SCULPT_TOOL_SNAKE_HOOK:
       br->alpha = 1.0f;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index ea3fb5624dd..a99b6e44d18 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -914,6 +914,7 @@ static bool sculpt_tool_needs_original(const char sculpt_tool)
               SCULPT_TOOL_LAYER,
               SCULPT_TOOL_DRAW_SHARP,
               SCULPT_TOOL_ELASTIC_DEFORM,
+              SCULPT_TOOL_SMOOTH,
               SCULPT_TOOL_POSE);
 }
 
@@ -2859,7 +2860,7 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
   }
 }
 
-static void grids_neighbor_average(SculptSession *ss, float result[3], int index)
+static void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
 {
   float avg[3] = {0.0f, 0.0f, 0.0f};
   int total = 0;
@@ -3155,7 +3156,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
       }
       else {
         float avg[3], val[3];
-        grids_neighbor_average(ss, avg, vd.index);
+        SCULPT_neighbor_coords_average(ss, avg, vd.index);
         sub_v3_v3v3(val, avg, vd.co);
         madd_v3_v3v3fl(val, vd.co, val, fade);
         sculpt_clip(sd, ss, vd.co, val);
@@ -3254,6 +3255,153 @@ static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
   SculptSession *ss = ob->sculpt;
   smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
 }
+/* HC Smooth Algorithm. */
+/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
+
+static void surface_smooth_laplacian_step(SculptSession *ss,
+                                          float *disp,
+                                          const float co[3],
+                                          float (*laplacian_disp)[3],
+                                          const int v_index,
+                                          const float origco[3],
+                                          const float alpha)
+{
+  float laplacian_smooth_co[3];
+  float weigthed_o[3], weigthed_q[3], d[3];
+  SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index);
+
+  mul_v3_v3fl(weigthed_o, origco, alpha);
+  mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
+  add_v3_v3v3(d, weigthed_o, weigthed_q);
+  sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
+
+  sub_v3_v3v3(disp, laplacian_smooth_co, co);
+}
+
+static void surface_smooth_displace_step(SculptSession *ss,
+                                         float *co,
+                                         float (*laplacian_disp)[3],
+                                         const int v_index,
+                                         const float beta,
+                                         const float fade)
+{
+  float b_avg[3] = {0.0f, 0.0f, 0.0f};
+  float b_current_vertex[3];
+  int total = 0;
+  SculptVertexNeighborIter ni;
+  sculpt_vertex_neighbors_iter_begin(ss, v_index, ni)
+  {
+    add_v3_v3(b_avg, laplacian_disp[ni.index]);
+    total++;
+  }
+  sculpt_vertex_neighbors_iter_end(ni);
+  if (total > 0) {
+    mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / (float)total);
+    madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta);
+    mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f));
+    sub_v3_v3(co, b_current_vertex);
+  }
+}
+
+static void do_surface_smooth_brush_laplacian_task_cb_ex(void *__restrict userdata,
+                                                         const int n,
+                                                         const TaskParallelTLS *__restrict tls)
+{
+  SculptThreadedTaskData *data = userdata;
+  SculptSession *ss = data->ob->sculpt;
+  const Brush *brush = data->brush;
+  const float bstrength = ss->cache->bstrength;
+  float alpha = brush->surface_smooth_shape_preservation;
+
+  PBVHVertexIter vd;
+  SculptOrigVertData orig_data;
+
+  SculptBrushTest test;
+  SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+      ss, &test, data->brush->falloff_shape);
+
+  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)
+  {
+    SCULPT_orig_vert_data_update(&orig_data, &vd);
+    if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+      const float fade =
+          bstrength *
+          SCULPT_brush_strength_factor(
+              ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+
+      float disp[3];
+      surface_smooth_laplacian_step(ss,
+                                    disp,
+                                    vd.co,
+                                    ss->cache->surface_smooth_laplacian_disp,
+                                    vd.index,
+                                    orig_data.co,
+                                    alpha);
+      madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
+    }
+    BKE_pbvh_vertex_iter_end;
+  }
+}
+
+static void do_surface_smooth_brush_displace_task_cb_ex(void *__restrict userdata,
+                                                        const int n,
+                                                        const TaskParallelTLS *__restrict tls)
+{
+  SculptThreadedTaskData *data = userdata;
+  SculptSession *ss = data->ob->sculpt;
+  const Brush *brush = data->brush;
+  const float bstrength = ss->cache->bstrength;
+  const float beta = brush->surface_smooth_current_vertex;
+
+  PBVHVertexIter vd;
+
+  SculptBrushTest test;
+  SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+      ss, &test, data->brush->falloff_shape);
+
+  BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+  {
+    if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+      const float fade =
+          bstrength *
+          SCULPT_brush_strength_factor(
+              ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+      surface_smooth_displace_step(
+          ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
+    }
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static void do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+  Brush *brush = BKE_paint_brush(&sd->paint);
+  SculptSession *ss = ob->sculpt;
+
+  if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0) {
+    ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
+        SCULPT_vertex_count_get(ss) * 3 * sizeof(float), "HC smooth laplacian b");
+  }
+
+  /* Threaded loop over nodes. */
+  SculptThreadedTaskData data = {
+      .sd = sd,
+      .ob = ob,
+      .brush = brush,
+      .nodes = nodes,
+  };
+
+  PBVHParallelSettings settings;
+  BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+  for (int i = 0; i < brush->surface_smooth_iterations; i++) {
+    BKE_pbvh_parallel_range(
+        0, totnode, &data, do_surface_smooth_brush_laplacian_task_cb_ex, &settings);
+    BKE_pbvh_parallel_range(
+        0, totnode, &data, do_surface_smooth_brush_displace_task_cb_ex, &settings);
+  }
+}
 
 static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
                                           const int n,
@@ -6010,7 +6158,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
         do_draw_brush(sd, ob, nodes, totnode);
         break;
       case SCULPT_TOOL_SMOOTH:
-        do_smooth_brush(sd, ob, nodes, totnode);
+        if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
+          do_smooth_brush(sd, ob, nodes, totnode);
+        }
+        else if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE) {
+          do_surface_smooth_brush(sd, ob, nodes, totnode);
+        }
         break;
       case SCULPT_TOOL_CREASE:
         do_crease_brush(sd, ob,

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list