[Bf-blender-cvs] [70c1aaf59ba] master: Sculpt: Elastic Deform Brush

Pablo Dobarro noreply at git.blender.org
Mon Sep 9 15:33:46 CEST 2019


Commit: 70c1aaf59ba91eede3d519caf9052ca3ef94ea9b
Author: Pablo Dobarro
Date:   Fri Sep 6 23:14:57 2019 +0200
Branches: master
https://developer.blender.org/rB70c1aaf59ba91eede3d519caf9052ca3ef94ea9b

Sculpt: Elastic Deform Brush

This patch implements the paper "Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity" https://graphics.pixar.com/library/Kelvinlets/paper.pdf

It includes grab, biscale grab, triscale grab, scale and twist.
All deformation modes are accessible under the same tool. This helps to keep the code organized and it should not make any difference to the user when a better brush management system is implemented.

Reviewed By: brecht

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

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

M	release/scripts/startup/bl_ui/space_view3d_toolbar.py
M	source/blender/blenkernel/intern/brush.c
M	source/blender/blenloader/intern/versioning_280.c
M	source/blender/editors/sculpt_paint/paint_stroke.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/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 89d771b7026..5bc4883d1ea 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -369,6 +369,13 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
             row = col.row()
             row.prop(brush, "normal_radius_factor", slider=True)
 
+            if brush.sculpt_tool == 'ELASTIC_DEFORM':
+                col.separator()
+                row = col.row()
+                row.prop(brush, "elastic_deform_type")
+                row = col.row()
+                row.prop(brush, "elastic_deform_compressibility", slider=True)
+
             # topology_rake_factor
             if (
                     capabilities.has_topology_rake and
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index cb408d25a01..f5f7fb71a64 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -901,6 +901,7 @@ void BKE_brush_sculpt_reset(Brush *br)
       br->add_col[2] = 0.750000;
       break;
     case SCULPT_TOOL_GRAB:
+    case SCULPT_TOOL_ELASTIC_DEFORM:
     case SCULPT_TOOL_SNAKE_HOOK:
     case SCULPT_TOOL_THUMB:
       br->size = 75;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 1784cd0ab95..3bccf65f4e7 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3834,5 +3834,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
         }
       }
     }
+
+    /* Elatic deform brush */
+    for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+      if (br->ob_mode & OB_MODE_SCULPT && br->elastic_deform_compressibility == 0.0f) {
+        br->elastic_deform_compressibility = 0.5f;
+      }
+    }
   }
 }
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 18f087e8c7b..0072888cb8d 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -221,6 +221,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
     case PAINT_MODE_SCULPT:
       if (ELEM(brush->sculpt_tool,
                SCULPT_TOOL_GRAB,
+               SCULPT_TOOL_ELASTIC_DEFORM,
                SCULPT_TOOL_ROTATE,
                SCULPT_TOOL_SNAKE_HOOK,
                SCULPT_TOOL_THUMB)) {
@@ -251,7 +252,11 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
 {
   switch (mode) {
     case PAINT_MODE_SCULPT:
-      if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB)) {
+      if (ELEM(brush->sculpt_tool,
+               SCULPT_TOOL_GRAB,
+               SCULPT_TOOL_ROTATE,
+               SCULPT_TOOL_THUMB,
+               SCULPT_TOOL_ELASTIC_DEFORM)) {
         return false;
       }
       else {
@@ -949,6 +954,7 @@ static bool sculpt_is_grab_tool(Brush *br)
 {
   return ELEM(br->sculpt_tool,
               SCULPT_TOOL_GRAB,
+              SCULPT_TOOL_ELASTIC_DEFORM,
               SCULPT_TOOL_THUMB,
               SCULPT_TOOL_ROTATE,
               SCULPT_TOOL_SNAKE_HOOK);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 4ad69e5de2a..dce8ea105e4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -358,7 +358,8 @@ static bool sculpt_tool_needs_original(const char sculpt_tool)
               SCULPT_TOOL_ROTATE,
               SCULPT_TOOL_THUMB,
               SCULPT_TOOL_LAYER,
-              SCULPT_TOOL_DRAW_SHARP);
+              SCULPT_TOOL_DRAW_SHARP,
+              SCULPT_TOOL_ELASTIC_DEFORM);
 }
 
 static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
@@ -388,6 +389,7 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
                SCULPT_TOOL_LAYER,
                SCULPT_TOOL_NUDGE,
                SCULPT_TOOL_ROTATE,
+               SCULPT_TOOL_ELASTIC_DEFORM,
                SCULPT_TOOL_THUMB) ||
 
           (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
@@ -1445,6 +1447,9 @@ static float brush_strength(const Sculpt *sd,
     case SCULPT_TOOL_ROTATE:
       return alpha * pressure * feather;
 
+    case SCULPT_TOOL_ELASTIC_DEFORM:
+      return root_alpha * feather;
+
     default:
       return 0;
   }
@@ -2918,6 +2923,252 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
   BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
 }
 
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+typedef struct KelvinletParams {
+  float f;
+  float a;
+  float b;
+  float c;
+  float radius_scaled;
+} KelvinletParams;
+
+static int sculpt_kelvinlet_get_scale_iteration_count(eBrushElasticDeformType type)
+{
+  if (type == BRUSH_ELASTIC_DEFORM_GRAB) {
+    return 1;
+  }
+  if (type == BRUSH_ELASTIC_DEFORM_GRAB_BISCALE) {
+    return 2;
+  }
+  if (type == BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE) {
+    return 3;
+  }
+  return 0;
+}
+
+static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3],
+                                                        const float vertex_co[3],
+                                                        const float location[3],
+                                                        float normal[3],
+                                                        KelvinletParams *p),
+                                      float r_disp[3],
+                                      const float vertex_co[3],
+                                      const float location[3],
+                                      float normal[3],
+                                      KelvinletParams *p)
+{
+  float k[4][3], k_it[4][3];
+  kelvinlet(k[0], vertex_co, location, normal, p);
+  copy_v3_v3(k_it[0], k[0]);
+  mul_v3_fl(k_it[0], 0.5f);
+  add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
+  kelvinlet(k[1], k_it[0], location, normal, p);
+  copy_v3_v3(k_it[1], k[1]);
+  mul_v3_fl(k_it[1], 0.5f);
+  add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
+  kelvinlet(k[2], k_it[1], location, normal, p);
+  copy_v3_v3(k_it[2], k[2]);
+  add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
+  sub_v3_v3v3(k_it[2], k_it[2], location);
+  kelvinlet(k[3], k_it[2], location, normal, p);
+  copy_v3_v3(r_disp, k[0]);
+  madd_v3_v3fl(r_disp, k[1], 2);
+  madd_v3_v3fl(r_disp, k[2], 2);
+  add_v3_v3(r_disp, k[3]);
+  mul_v3_fl(r_disp, 1.0f / 6.0f);
+}
+
+/* Regularized Kelvinlets: Formula (16) */
+static void sculpt_kelvinlet_scale(float disp[3],
+                                   const float vertex_co[3],
+                                   const float location[3],
+                                   float UNUSED(normal[3]),
+                                   KelvinletParams *p)
+{
+  float r_v[3];
+  sub_v3_v3v3(r_v, vertex_co, location);
+  float r = len_v3(r_v);
+  float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+  float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) +
+            ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+  float fade = u * p->c;
+  mul_v3_v3fl(disp, r_v, fade * p->f);
+}
+
+/* Regularized Kelvinlets: Formula (15) */
+static void sculpt_kelvinlet_twist(float disp[3],
+                                   const float vertex_co[3],
+                                   const float location[3],
+                                   float normal[3],
+                                   KelvinletParams *p)
+{
+  float r_v[3], q_r[3];
+  sub_v3_v3v3(r_v, vertex_co, location);
+  float r = len_v3(r_v);
+  float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled);
+  float u = -p->a * ((1.0f / (r_e * r_e * r_e))) +
+            ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e));
+  float fade = u * p->c;
+  cross_v3_v3v3(q_r, normal, r_v);
+  mul_v3_v3fl(disp, q_r, fade * p->f);
+}
+
+static void do_elastic_deform_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 *grab_delta = data->grab_delta;
+  const float *location = ss->cache->location;
+
+  PBVHVertexIter vd;
+  SculptOrigVertData orig_data;
+  float(*proxy)[3];
+
+  const float bstrength = ss->cache->bstrength;
+
+  sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+  proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+  /* Maybe this can be exposed to the user */
+  float radius_e[3] = {1.0f, 2.0f, 2.0f};
+  float r_e[3];
+  float kvl[3];
+  float radius_scaled[3];
+
+  radius_scaled[0] = ss->cache->radius * radius_e[0];
+  radius_scaled[1] = radius_scaled[0] * radius_e[1];
+  radius_scaled[2] = radius_scaled[1] * radius_e[2];
+
+  float shear_modulus = 1.0f;
+  float poisson_ratio = brush->elastic_deform_compressibility;
+
+  float a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
+  float b = a / (4.0f * (1.0f - poisson_ratio));
+  float c = 2 * (3.0f * a - 2.0f * b);
+
+  float dir;
+  if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+    dir = 1.0f;
+  }
+  else {
+    dir = -1.0f;
+  }
+
+  if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+    int symm = ss->cache->mirror_symmetry_pass;
+    if (symm == 1 || symm == 2 || symm == 4 || symm == 7) {
+      dir = -dir;
+    }
+  }
+  BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+  {
+    sculpt_orig_vert_data_update(&orig_data, &vd);
+    float fade, u, final_disp[3], weights[3];
+    float r = len_v3v3(location, orig_data.co);
+    KelvinletParams params;
+    params.a = a;
+    params.b = b;
+    params.c = c;
+    params.radius_scaled = radius_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list