[Bf-blender-cvs] [bfbee878313] master: Sculpt: Pose Brush

Pablo Dobarro noreply at git.blender.org
Mon Sep 9 17:54:49 CEST 2019


Commit: bfbee8783138c87c0f805bcb69540f7391bf2ad3
Author: Pablo Dobarro
Date:   Mon Sep 9 17:44:08 2019 +0200
Branches: master
https://developer.blender.org/rBbfbee8783138c87c0f805bcb69540f7391bf2ad3

Sculpt: Pose Brush

This brush lets the user pose a model simulating an armature-like deformation. The pivot point for rotation is calculated automatically based on the radius of the brush and the topology of the model.

Reviewed By: brecht

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

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

M	source/blender/blenkernel/intern/brush.c
M	source/blender/editors/sculpt_paint/paint_stroke.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/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index f5f7fb71a64..bdc836225c9 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -902,6 +902,7 @@ void BKE_brush_sculpt_reset(Brush *br)
       break;
     case SCULPT_TOOL_GRAB:
     case SCULPT_TOOL_ELASTIC_DEFORM:
+    case SCULPT_TOOL_POSE:
     case SCULPT_TOOL_SNAKE_HOOK:
     case SCULPT_TOOL_THUMB:
       br->size = 75;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 0072888cb8d..d2173ed0d96 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -222,6 +222,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
       if (ELEM(brush->sculpt_tool,
                SCULPT_TOOL_GRAB,
                SCULPT_TOOL_ELASTIC_DEFORM,
+               SCULPT_TOOL_POSE,
                SCULPT_TOOL_ROTATE,
                SCULPT_TOOL_SNAKE_HOOK,
                SCULPT_TOOL_THUMB)) {
@@ -256,7 +257,8 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
                SCULPT_TOOL_GRAB,
                SCULPT_TOOL_ROTATE,
                SCULPT_TOOL_THUMB,
-               SCULPT_TOOL_ELASTIC_DEFORM)) {
+               SCULPT_TOOL_ELASTIC_DEFORM,
+               SCULPT_TOOL_POSE)) {
         return false;
       }
       else {
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 0a4c77b5656..a5327ff571c 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -30,6 +30,7 @@
 #include "BLI_hash.h"
 #include "BLI_gsqueue.h"
 #include "BLI_stack.h"
+#include "BLI_gsqueue.h"
 #include "BLI_task.h"
 #include "BLI_utildefines.h"
 #include "BLI_ghash.h"
@@ -343,6 +344,25 @@ static void sculpt_vertex_mask_clamp(SculptSession *ss, int index, float min, fl
   }
 }
 
+static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
+{
+  bool is_in_symmetry_area = true;
+  for (int i = 0; i < 3; i++) {
+    char symm_it = 1 << i;
+    if (symm & symm_it) {
+      if (pco[i] == 0.0f) {
+        if (vco[i] > 0.0f) {
+          is_in_symmetry_area = false;
+        }
+      }
+      if (vco[i] * pco[i] < 0.0f) {
+        is_in_symmetry_area = false;
+      }
+    }
+  }
+  return is_in_symmetry_area;
+}
+
 static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
                                           const int n,
                                           const TaskParallelTLS *__restrict UNUSED(tls))
@@ -401,6 +421,7 @@ int sculpt_nearest_vertex_get(
       .max_distance_squared = max_distance * max_distance,
       .nearest_vertex_index = -1,
   };
+
   copy_v3_v3(task_data.nearest_vertex_search_co, co);
 
   BLI_mutex_init(&task_data.mutex);
@@ -470,12 +491,13 @@ static bool sculpt_tool_needs_original(const char sculpt_tool)
               SCULPT_TOOL_THUMB,
               SCULPT_TOOL_LAYER,
               SCULPT_TOOL_DRAW_SHARP,
-              SCULPT_TOOL_ELASTIC_DEFORM);
+              SCULPT_TOOL_ELASTIC_DEFORM,
+              SCULPT_TOOL_POSE);
 }
 
 static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
 {
-  return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER);
+  return ELEM(sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE);
 }
 
 static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
@@ -1698,6 +1720,7 @@ static float brush_strength(const Sculpt *sd,
       return alpha * pressure * feather;
 
     case SCULPT_TOOL_ELASTIC_DEFORM:
+    case SCULPT_TOOL_POSE:
       return root_alpha * feather;
 
     default:
@@ -3446,6 +3469,240 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
   BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
 }
 
+static void do_pose_brush_task_cb_ex(void *__restrict userdata,
+                                     const int n,
+                                     const TaskParallelTLS *__restrict tls)
+{
+  SculptThreadedTaskData *data = userdata;
+  SculptSession *ss = data->ob->sculpt;
+
+  PBVHVertexIter vd;
+  float disp[3], val[3];
+  float final_pos[3];
+
+  SculptOrigVertData orig_data;
+  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 (check_vertex_pivot_symmetry(
+            orig_data.co, data->pose_initial_co, ss->cache->mirror_symmetry_pass)) {
+      copy_v3_v3(val, orig_data.co);
+      mul_m4_v3(data->transform_trans_inv, val);
+      mul_m4_v3(data->transform_rot, val);
+      mul_m4_v3(data->transform_trans, val);
+      sub_v3_v3v3(disp, val, orig_data.co);
+
+      mul_v3_fl(disp, ss->cache->pose_factor[vd.index]);
+      float mask = vd.mask ? *vd.mask : 0.0f;
+      mul_v3_fl(disp, 1.0f - mask);
+      add_v3_v3v3(final_pos, orig_data.co, disp);
+      copy_v3_v3(vd.co, final_pos);
+
+      if (vd.mvert) {
+        vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+      }
+    }
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+  SculptSession *ss = ob->sculpt;
+  Brush *brush = BKE_paint_brush(&sd->paint);
+  float grab_delta[3], rot_quat[4], initial_v[3], current_v[3], temp[3];
+  float pose_origin[3];
+  float pose_initial_co[3];
+  float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
+
+  copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+  copy_v3_v3(pose_origin, ss->cache->pose_origin);
+  flip_v3(pose_origin, (char)ss->cache->mirror_symmetry_pass);
+
+  copy_v3_v3(pose_initial_co, ss->cache->pose_initial_co);
+  flip_v3(pose_initial_co, (char)ss->cache->mirror_symmetry_pass);
+
+  sub_v3_v3v3(initial_v, pose_initial_co, pose_origin);
+  normalize_v3(initial_v);
+
+  add_v3_v3v3(temp, pose_initial_co, grab_delta);
+  sub_v3_v3v3(current_v, temp, pose_origin);
+  normalize_v3(current_v);
+
+  rotation_between_vecs_to_quat(rot_quat, initial_v, current_v);
+  unit_m4(transform_rot);
+  unit_m4(transform_trans);
+  quat_to_mat4(transform_rot, rot_quat);
+  translate_m4(transform_trans, pose_origin[0], pose_origin[1], pose_origin[2]);
+  invert_m4_m4(transform_trans_inv, transform_trans);
+
+  SculptThreadedTaskData data = {
+      .sd = sd,
+      .ob = ob,
+      .brush = brush,
+      .nodes = nodes,
+      .grab_delta = grab_delta,
+      .pose_origin = pose_origin,
+      .pose_initial_co = pose_initial_co,
+      .transform_rot = transform_rot,
+      .transform_trans = transform_trans,
+      .transform_trans_inv = transform_trans_inv,
+  };
+
+  TaskParallelSettings settings;
+  BLI_parallel_range_settings_defaults(&settings);
+  settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+  BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+}
+
+static void pose_brush_init_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)
+  {
+    SculptVertexNeighborIter ni;
+    float avg = 0;
+    int total = 0;
+    sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
+    {
+      avg += ss->cache->pose_factor[ni.index];
+      total++;
+    }
+    sculpt_vertex_neighbors_iter_end(ni);
+
+    if (total > 0) {
+      ss->cache->pose_factor[vd.index] = avg / (float)total;
+    }
+  }
+  BKE_pbvh_vertex_iter_end;
+}
+
+static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
+                                                            float br_co[3],
+                                                            float radius,
+                                                            char symm)
+{
+  for (char i = 0; i <= symm; ++i) {
+    if (is_symmetry_iteration_valid(i, symm)) {
+      float location[3];
+      flip_v3_v3(location, br_co, (char)i);
+      if (len_v3v3(location, vertex) < radius) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
+{
+  sculpt_vertex_random_access_init(ss);
+
+  ss->cache->pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
+
+  copy_v3_v3(ss->cache->pose_initial_co, ss->cache->location);
+
+  char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
+                                       "Visited vertices");
+  BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
+                                                  "not visited vertices stack");
+
+  float tot_co = 0;
+  zero_v3(ss->cache->pose_origin);
+
+  VertexTopologyIterator mevit;
+
+  /* Add active vertex and symmetric vertices to the stack. */
+  const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+  for (char i = 0; i <= symm; ++i) {
+    if (is_symmetry_iteration_valid(i, symm)) {
+      float location[3];
+      flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), (char)i);
+      if (i == 0) {
+        mevit.v = sculpt_active_vertex_get(ss);
+      }
+      else {
+        mevit.v = sculpt_nearest_vertex_get(
+            sd, ob, location, ss->cache->radius * ss->cache->radius, false);
+      }
+      if (mevit.v != -1) {
+        mevit.it = 1;
+        BLI_stack_push(not_visited_vertices, &mevit);
+      }
+    }
+  }
+
+  /* Flood fill the internal pose brush factor. Calculate the pose rotation point based on the
+   * boundaries of the brush factor*/
+  while (!BLI_stack_is_empty(not_visited_vertices)) {
+    VertexTopologyIterator c_mevit;
+    BLI_stack_pop(not_visited_vertices, &c_mevit);
+    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list