[Bf-blender-cvs] [3778f168f68] master: Sculpt: Pose Brush Face Sets FK mode

Pablo Dobarro noreply at git.blender.org
Mon Jun 1 22:30:47 CEST 2020


Commit: 3778f168f688a6c76f5c0b54262b1ed82deb0c84
Author: Pablo Dobarro
Date:   Tue May 26 23:54:53 2020 +0200
Branches: master
https://developer.blender.org/rB3778f168f688a6c76f5c0b54262b1ed82deb0c84

Sculpt: Pose Brush Face Sets FK mode

This Pose Brush origin mode simulates an FK deformation in the entire
model when clicking on the face sets, as they were controls of a fully
rigged character. Combined with the previous Face Sets modes that allow
creating IK chains, the pose brush should now be able to simulate most
of the common rigs deformations.

Reviewed By: sergey

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

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

M	release/scripts/startup/bl_ui/properties_paint_common.py
M	source/blender/editors/sculpt_paint/sculpt_pose.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/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 5fadb31c83f..1612cce3c51 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -623,7 +623,7 @@ def brush_settings(layout, context, brush, popover=False):
             layout.prop(brush, "pose_origin_type")
             layout.prop(brush, "pose_offset")
             layout.prop(brush, "pose_smooth_iterations")
-            if brush.pose_deform_type == 'ROTATE_TWIST':
+            if brush.pose_deform_type == 'ROTATE_TWIST' and brush.pose_origin_type in ('TOPOLOGY','FACE_SETS'):
               layout.prop(brush, "pose_ik_segments")
             layout.prop(brush, "use_pose_ik_anchored")
             layout.separator()
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 35f4870fa12..7c9caeb4340 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -401,6 +401,13 @@ typedef struct PoseFloodFillData {
    * that have the current face set. */
   float fallback_origin[3];
   int fallback_count;
+
+  /* Face Set FK mode. */
+  int *floodfill_it;
+  float *fk_weights;
+  int initial_face_set;
+  int masked_face_set_it;
+  int masked_face_set;
 } PoseFloodFillData;
 
 static bool pose_topology_floodfill_cb(
@@ -806,6 +813,92 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
   return ik_chain;
 }
 
+static bool pose_face_sets_fk_find_masked_floodfill_cb(
+    SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+  PoseFloodFillData *data = userdata;
+
+  if (!is_duplicate) {
+    data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1;
+  }
+  else {
+    data->floodfill_it[to_v] = data->floodfill_it[from_v];
+  }
+
+  const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v);
+  if (SCULPT_vertex_has_unique_face_set(ss, to_v) &&
+      !SCULPT_vertex_has_unique_face_set(ss, from_v) &&
+      SCULPT_vertex_has_face_set(ss, from_v, to_face_set)) {
+    if (data->floodfill_it[to_v] > data->masked_face_set_it) {
+      data->masked_face_set = to_face_set;
+      data->masked_face_set_it = data->floodfill_it[to_v];
+    }
+  }
+
+  return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set);
+}
+
+static bool pose_face_sets_fk_set_weights_floodfill_cb(
+    SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+{
+  PoseFloodFillData *data = userdata;
+  data->fk_weights[to_v] = 1.0f;
+  return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set);
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
+    Sculpt *sd, Object *ob, SculptSession *ss, const float radius, const float *initial_location)
+{
+  const int totvert = SCULPT_vertex_count_get(ss);
+
+  SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
+
+  const int active_vertex = SCULPT_active_vertex_get(ss);
+  const int active_face_set = SCULPT_active_face_set_get(ss);
+
+  SculptFloodFill flood;
+  SCULPT_floodfill_init(ss, &flood);
+  SCULPT_floodfill_add_initial(&flood, active_vertex);
+  PoseFloodFillData fdata;
+  fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration");
+  fdata.floodfill_it[active_vertex] = 1;
+  fdata.initial_face_set = active_face_set;
+  fdata.masked_face_set = SCULPT_FACE_SET_NONE;
+  fdata.masked_face_set_it = 0;
+  SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_find_masked_floodfill_cb, &fdata);
+  SCULPT_floodfill_free(&flood);
+
+  int count = 0;
+  float origin_acc[3] = {0.0f};
+  for (int i = 0; i < totvert; i++) {
+    if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
+        SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) {
+      add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i));
+      count++;
+    }
+  }
+  MEM_freeN(fdata.floodfill_it);
+
+  if (count > 0) {
+    copy_v3_v3(ik_chain->segments[0].orig, origin_acc);
+    mul_v3_fl(ik_chain->segments[0].orig, 1.0f / count);
+  }
+  else {
+    zero_v3(ik_chain->segments[0].orig);
+  }
+
+  copy_v3_v3(ik_chain->segments[0].head, initial_location);
+
+  SCULPT_floodfill_init(ss, &flood);
+  SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius);
+  fdata.fk_weights = ik_chain->segments[0].weights;
+  SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_set_weights_floodfill_cb, &fdata);
+  SCULPT_floodfill_free(&flood);
+
+  pose_ik_chain_origin_heads_init(ik_chain, initial_location);
+  return ik_chain;
+}
+
 SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
                                              Object *ob,
                                              SculptSession *ss,
@@ -820,6 +913,9 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
     case BRUSH_POSE_ORIGIN_FACE_SETS:
       return pose_ik_chain_init_face_sets(sd, ob, ss, br, radius);
       break;
+    case BRUSH_POSE_ORIGIN_FACE_SETS_FK:
+      return pose_ik_chain_init_face_sets_fk(sd, ob, ss, radius, initial_location);
+      break;
   }
   return NULL;
 }
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 2e449f10563..be7c894b4e4 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -339,6 +339,7 @@ typedef enum eBrushPoseDeformType {
 typedef enum eBrushPoseOriginType {
   BRUSH_POSE_ORIGIN_TOPOLOGY = 0,
   BRUSH_POSE_ORIGIN_FACE_SETS = 1,
+  BRUSH_POSE_ORIGIN_FACE_SETS_FK = 2,
 } eBrushPoseOriginType;
 
 /* Gpencilsettings.Vertex_mode */
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 9e78eec9c25..209e5a1ff8b 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1978,6 +1978,11 @@ static void rna_def_brush(BlenderRNA *brna)
        0,
        "Face Sets",
        "Creates a pose segment per face sets, starting from the active face set"},
+      {BRUSH_POSE_ORIGIN_FACE_SETS_FK,
+       "FACE_SETS_FK",
+       0,
+       "Face Sets FK",
+       "Simulates an FK deformation using the Face Set under the cursor as control"},
       {0, NULL, 0, NULL, NULL},
   };



More information about the Bf-blender-cvs mailing list