[Bf-blender-cvs] [d23894d3ef3] master: Sculpt: Multires Displacement Smear

Pablo Dobarro noreply at git.blender.org
Wed Dec 16 17:09:26 CET 2020


Commit: d23894d3ef3f019eeb88ef3da77e8416c6f70f29
Author: Pablo Dobarro
Date:   Fri Dec 11 22:49:49 2020 +0100
Branches: master
https://developer.blender.org/rBd23894d3ef3f019eeb88ef3da77e8416c6f70f29

Sculpt: Multires Displacement Smear

This tool implements smearing for multires displacement over the limit
surface, similar to how smearing for colors and topology slide works.
When used the displacement values of the vertices "slide" over the
topology, creating the effect of smearing the surface detail.

As the brush just modifies displacement values instead of coordinates,
the total displacement of the affected area doesn't change. This means
that this smearing effect can be used multiple times over the same area
without generating any artifacts in the topology.

When the brush is used with the pinch or expand smear modes,
displacement differences are pushed into the same area, creating hard
surface effects without pinching the topology.

As any other brush that relies on the limit surface (like displacement
erasers), this will work better after using apply base.

Reviewed By: sergey, JulienKaspar, dbystedt

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

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

M	release/scripts/startup/bl_ui/properties_paint_common.py
M	source/blender/blenkernel/intern/brush.c
M	source/blender/blenloader/intern/versioning_defaults.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/makesdna/DNA_brush_enums.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 86221ebce59..5d241e8e216 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -764,6 +764,10 @@ def brush_settings(layout, context, brush, popover=False):
                 col.prop(brush, "surface_smooth_current_vertex")
                 col.prop(brush, "surface_smooth_iterations")
 
+        elif sculpt_tool == 'DISPLACEMENT_SMEAR':
+            col = layout.column()
+            col.prop(brush, "smear_deform_type")
+
         elif sculpt_tool == 'MASK':
             layout.row().prop(brush, "mask_tool", expand=True)
 
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 33686cea4fc..9a954a89cad 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1834,6 +1834,14 @@ void BKE_brush_sculpt_reset(Brush *br)
       br->flag &= ~BRUSH_SPACE_ATTEN;
       br->curve_preset = BRUSH_CURVE_SPHERE;
       break;
+    case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+      br->alpha = 1.0f;
+      br->spacing = 5;
+      br->hardness = 0.7f;
+      br->flag &= ~BRUSH_ALPHA_PRESSURE;
+      br->flag &= ~BRUSH_SPACE_ATTEN;
+      br->curve_preset = BRUSH_CURVE_SMOOTHER;
+      break;
     default:
       break;
   }
@@ -1898,6 +1906,7 @@ void BKE_brush_sculpt_reset(Brush *br)
     case SCULPT_TOOL_MASK:
     case SCULPT_TOOL_DRAW_FACE_SETS:
     case SCULPT_TOOL_DISPLACEMENT_ERASER:
+    case SCULPT_TOOL_DISPLACEMENT_SMEAR:
       br->add_col[0] = 0.75f;
       br->add_col[1] = 0.75f;
       br->add_col[2] = 0.75f;
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 2d75b046366..198f65b9794 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -739,6 +739,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
       brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER;
     }
 
+    brush_name = "Multires Displacement Smear";
+    brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+    if (!brush) {
+      brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+      id_us_min(&brush->id);
+      brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_SMEAR;
+    }
+
     /* Use the same tool icon color in the brush cursor */
     for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
       if (brush->ob_mode & OB_MODE_SCULPT) {
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 80a32682325..26db2673335 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1227,6 +1227,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
               SCULPT_TOOL_SMOOTH,
               SCULPT_TOOL_LAYER,
               SCULPT_TOOL_POSE,
+              SCULPT_TOOL_DISPLACEMENT_SMEAR,
               SCULPT_TOOL_BOUNDARY,
               SCULPT_TOOL_CLOTH,
               SCULPT_TOOL_PAINT,
@@ -2362,6 +2363,7 @@ static float brush_strength(const Sculpt *sd,
       final_pressure = pressure * pressure;
       return final_pressure * overlap * feather;
     case SCULPT_TOOL_SMEAR:
+    case SCULPT_TOOL_DISPLACEMENT_SMEAR:
       return alpha * pressure * overlap * feather;
     case SCULPT_TOOL_CLAY_STRIPS:
       /* Clay Strips needs less strength to compensate the curve. */
@@ -3103,6 +3105,147 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node
 
 /** \} */
 
+/** \name Sculpt Multires Displacement Smear Brush
+ * \{ */
+
+static void do_displacement_smear_brush_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 = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+  SculptBrushTest test;
+  SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+      ss, &test, data->brush->falloff_shape);
+  const int thread_id = BLI_task_parallel_thread_id(tls);
+
+  PBVHVertexIter vd;
+  BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+  {
+    if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+      continue;
+    }
+    const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+                                                                brush,
+                                                                vd.co,
+                                                                sqrtf(test.dist),
+                                                                vd.no,
+                                                                vd.fno,
+                                                                vd.mask ? *vd.mask : 0.0f,
+                                                                vd.index,
+                                                                thread_id);
+
+    float current_disp[3];
+    float current_disp_norm[3];
+    float interp_limit_surface_disp[3];
+
+    copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
+
+    switch (brush->smear_deform_type) {
+      case BRUSH_SMEAR_DEFORM_DRAG:
+        sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+        break;
+      case BRUSH_SMEAR_DEFORM_PINCH:
+        sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+        break;
+      case BRUSH_SMEAR_DEFORM_EXPAND:
+        sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+        break;
+    }
+
+    normalize_v3_v3(current_disp_norm, current_disp);
+    mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+    float weights_accum = 1.0f;
+
+    SculptVertexNeighborIter ni;
+    SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+      float vertex_disp[3];
+      float vertex_disp_norm[3];
+      float neighbor_limit_co[3];
+      SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+      sub_v3_v3v3(vertex_disp,
+                  ss->cache->limit_surface_co[ni.index],
+                  ss->cache->limit_surface_co[vd.index]);
+      const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
+      normalize_v3_v3(vertex_disp_norm, vertex_disp);
+      if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) {
+        const float disp_interp = clamp_f(
+            -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
+        madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
+        weights_accum += disp_interp;
+      }
+    }
+    SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+    mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
+
+    float new_co[3];
+    add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
+    interp_v3_v3v3(vd.co, vd.co, new_co, fade);
+
+    if (vd.mvert) {
+      vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+    }
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_store_prev_disp_task_cb_ex(
+    void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+  SculptThreadedTaskData *data = userdata;
+  SculptSession *ss = data->ob->sculpt;
+
+  PBVHVertexIter vd;
+  BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+  {
+    sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
+                SCULPT_vertex_co_get(ss, vd.index),
+                ss->cache->limit_surface_co[vd.index]);
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+  Brush *brush = BKE_paint_brush(&sd->paint);
+  SculptSession *ss = ob->sculpt;
+
+  BKE_curvemapping_init(brush->curve);
+
+  const int totvert = SCULPT_vertex_count_get(ss);
+  if (!ss->cache->prev_displacement) {
+    ss->cache->prev_displacement = MEM_malloc_arrayN(
+        totvert, sizeof(float[3]), "prev displacement");
+    ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+    for (int i = 0; i < totvert; i++) {
+      SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+      sub_v3_v3v3(ss->cache->prev_displacement[i],
+                  SCULPT_vertex_co_get(ss, i),
+                  ss->cache->limit_surface_co[i]);
+    }
+  }
+  /* Threaded loop over nodes. */
+  SculptThreadedTaskData data = {
+      .sd = sd,
+      .ob = ob,
+      .brush = brush,
+      .nodes = nodes,
+  };
+
+  TaskParallelSettings settings;
+  BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+  BLI_task_parallel_range(
+      0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
+  BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
 static void do_draw_brush_task_cb_ex(void *__restrict userdata,
                                      const int n,
                                      const TaskParallelTLS *__restrict tls)
@@ -5927,6 +6070,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
       case SCULPT_TOOL_DISPLACEMENT_ERASER:
         do_displacement_eraser_brush(sd, ob, nodes, totnode);
         break;
+      case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+        do_displacement_smear_brush(sd, ob, nodes, totnode);
+        break;
       case SCULPT_TOOL_PAINT:
         SCULPT_do_paint_brush(sd, ob, nodes, totnode);
         break;
@@ -6490,6 +6636,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
       return "Draw Face Sets";
     case SCULPT_TOOL_DISPLACEMENT_ERASER:
       return "Multires Displacement Eraser";
+    case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+      return "Multires Displacement Smear";
     case SCULPT_TOOL_PAINT:
       re

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list