[Bf-blender-cvs] [a47f694b865] master: Sculpt: Topology Slide/Relax

Pablo Dobarro noreply at git.blender.org
Thu Nov 21 18:55:45 CET 2019


Commit: a47f694b86524459aa51c73f6cd65daf9c36e625
Author: Pablo Dobarro
Date:   Thu Nov 21 18:57:26 2019 +0100
Branches: master
https://developer.blender.org/rBa47f694b86524459aa51c73f6cd65daf9c36e625

Sculpt: Topology Slide/Relax

This commit implements the Topology Slide/Relax brush and the Relax mesh filter.
These tools are designed to move the topology on top of the mesh without affecting the volume.
The Topology Slide/Relax brush slides the topology of the mesh in the direction of the stroke. When pressing shift, it has an alternative smooth mode similar to the Relax Brush in the sculpt branch. It should be way more stable and produce fewer artifacts.

Reviewed By: jbakker

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

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

M	source/blender/blenkernel/intern/brush.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/makesdna/DNA_brush_types.h
M	source/blender/makesrna/intern/rna_brush.c

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

diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 15a9b0b9c6a..8d256132aa4 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -926,6 +926,10 @@ void BKE_brush_sculpt_reset(Brush *br)
       br->curve_preset = BRUSH_CURVE_POW4;
       br->spacing = 5;
       break;
+    case SCULPT_TOOL_TOPOLOGY:
+      br->spacing = 10;
+      br->alpha = 1.0f;
+      break;
     case SCULPT_TOOL_CLAY:
       br->spacing = 6;
       br->normal_radius_factor = 0.75f;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b7fb49d357f..c30986a4d4b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1743,6 +1743,8 @@ static float brush_strength(const Sculpt *sd,
     case SCULPT_TOOL_DRAW_SHARP:
     case SCULPT_TOOL_LAYER:
       return alpha * flip * pressure * overlap * feather;
+    case SCULPT_TOOL_TOPOLOGY:
+      return alpha * pressure * overlap * feather * 2.0f;
     case SCULPT_TOOL_CLAY_STRIPS:
       /* Clay Strips needs less strength to compensate the curve */
       final_pressure = pressure * pressure * pressure;
@@ -3096,6 +3098,184 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
   BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
 }
 
+/* -------------------------------------------------------------------- */
+
+/** \name Sculpt Topology Brush
+ * \{ */
+
+static void do_topology_slide_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;
+
+  PBVHVertexIter vd;
+  SculptOrigVertData orig_data;
+  float(*proxy)[3];
+
+  sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+  proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+  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)
+  {
+    sculpt_orig_vert_data_update(&orig_data, &vd);
+    if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+      const float fade = tex_strength(ss,
+                                      brush,
+                                      orig_data.co,
+                                      sqrtf(test.dist),
+                                      orig_data.no,
+                                      NULL,
+                                      vd.mask ? *vd.mask : 0.0f,
+                                      vd.index,
+                                      tls->thread_id);
+      float current_disp[3];
+      float current_disp_norm[3];
+      float final_disp[3];
+      zero_v3(final_disp);
+      sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+      normalize_v3_v3(current_disp_norm, current_disp);
+      mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+      SculptVertexNeighborIter ni;
+      sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+      {
+        float vertex_disp[3];
+        float vertex_disp_norm[3];
+        sub_v3_v3v3(vertex_disp, sculpt_vertex_co_get(ss, ni.index), vd.co);
+        normalize_v3_v3(vertex_disp_norm, vertex_disp);
+        if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
+          madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
+        }
+      }
+      sculpt_vertex_neighbors_iter_end(ni);
+
+      mul_v3_v3fl(proxy[vd.i], final_disp, fade);
+
+      if (vd.mvert) {
+        vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+      }
+    }
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static void sculpt_relax_vertex(SculptSession *ss,
+                                PBVHVertexIter *vd,
+                                float factor,
+                                float *r_final_pos)
+{
+  float smooth_pos[3];
+  float final_disp[3];
+  int count = 0;
+  zero_v3(smooth_pos);
+
+  SculptVertexNeighborIter ni;
+  sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
+  {
+    add_v3_v3(smooth_pos, sculpt_vertex_co_get(ss, ni.index));
+    count++;
+  }
+  sculpt_vertex_neighbors_iter_end(ni);
+
+  if (count > 0) {
+    mul_v3_fl(smooth_pos, 1.0f / (float)count);
+  }
+
+  float plane[4];
+  float smooth_closest_plane[3];
+  float vno[3];
+  normal_short_to_float_v3(vno, vd->no);
+  plane_from_point_normal_v3(plane, vd->co, vno);
+  closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
+  sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
+
+  mul_v3_fl(final_disp, factor);
+  add_v3_v3v3(r_final_pos, vd->co, final_disp);
+}
+
+static void do_topology_relax_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;
+
+  PBVHVertexIter vd;
+  SculptOrigVertData orig_data;
+  float(*proxy)[3];
+
+  sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+  proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+  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)
+  {
+    sculpt_orig_vert_data_update(&orig_data, &vd);
+    if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+      const float fade = tex_strength(ss,
+                                      brush,
+                                      orig_data.co,
+                                      sqrtf(test.dist),
+                                      orig_data.no,
+                                      NULL,
+                                      vd.mask ? *vd.mask : 0.0f,
+                                      vd.index,
+                                      tls->thread_id);
+
+      sculpt_relax_vertex(ss, &vd, fade * bstrength, vd.co);
+      if (vd.mvert) {
+        vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+      }
+    }
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static void do_topology_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+  SculptSession *ss = ob->sculpt;
+  Brush *brush = BKE_paint_brush(&sd->paint);
+
+  if (ss->cache->first_time) {
+    return;
+  }
+
+  BKE_curvemapping_initialize(brush->curve);
+
+  SculptThreadedTaskData data = {
+      .sd = sd,
+      .ob = ob,
+      .brush = brush,
+      .nodes = nodes,
+  };
+
+  PBVHParallelSettings settings;
+  BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+  if (ss->cache->alt_smooth) {
+    for (int i = 0; i < 4; i++) {
+      BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+    }
+  }
+  else {
+    BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+  }
+}
+
+/** \} */
+
 /**
  * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
  */
@@ -5833,6 +6013,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
       case SCULPT_TOOL_ELASTIC_DEFORM:
         do_elastic_deform_brush(sd, ob, nodes, totnode);
         break;
+      case SCULPT_TOOL_TOPOLOGY:
+        do_topology_brush(sd, ob, nodes, totnode);
+        break;
     }
 
     if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
@@ -6346,6 +6529,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
       return "Pose Brush";
     case SCULPT_TOOL_MULTIPLANE_SCRAPE:
       return "Multiplane Scrape Brush";
+    case SCULPT_TOOL_TOPOLOGY:
+      return "Topology Slide/Relax Brush";
   }
 
   return "Sculpting";
@@ -6469,6 +6654,9 @@ static void sculpt_update_cache_invariants(
       cache->saved_mask_brush_tool = brush->mask_tool;
       brush->mask_tool = BRUSH_MASK_SMOOTH;
     }
+    else if (brush->sculpt_tool == SCULPT_TOOL_TOPOLOGY) {
+      /* Do nothing, this tool has its own smooth mode */
+    }
     else {
       Paint *p = &sd->paint;
       Brush *br;
@@ -6840,7 +7028,8 @@ static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss
   return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
           (brush->sculpt_tool == SCULPT_TOOL_SMOOTH) || (brush->autosmooth_factor > 0) ||
           ((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) ||
-          (brush->sculpt_tool == SCULPT_TOOL_POSE));
+          (brush->sculpt_tool == SCULPT_TOOL_POSE) ||
+          (brush->sculpt_tool == SCULPT_TOOL_TOPOLOGY));
 }
 
 static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
@@ -7444,6 +7633,7 @@ static void sculpt_stroke_update_step(bContext *C,
   }
 
   ss->cache->first_time = false;
+  copy_v3_v3(ss->cache->true_last_location, ss->cache->true_location);
 
   /* Cleanup */
   if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
@@ -7486,6 +7676,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
       if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
         brush->mask_tool = ss->cache->saved_mask_brush_tool;
       }
+      else if (brush->sculpt_tool == SCULPT_TOOL_TOPOLOGY) {
+        /* Do nothing */
+      }
       else {
         BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
         brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
@@ -8768,6 +8961,7 @@ typedef enum eSculptMeshFilterTypes {
   MESH_FILTER_INFLATE = 2,
   MESH_FILTER_SPHERE = 3,
   MESH_FILTER_RANDOM = 4,
+  MESH_FILTER_RELAX = 5,
 } eSculptMeshFilterTypes;
 
 static EnumPropertyItem prop_mesh_filter_types[] = {
@@ -8776,6 +8970,7 @@ static EnumPropertyItem prop_mesh_filter

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list