Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Dobarro <pablodp606@gmail.com>2020-05-27 00:54:53 +0300
committerPablo Dobarro <pablodp606@gmail.com>2020-06-01 23:30:01 +0300
commit3778f168f688a6c76f5c0b54262b1ed82deb0c84 (patch)
treec37d1fb2a4e91cd86b3033c42164ca88b8f47693 /source/blender/editors/sculpt_paint/sculpt_pose.c
parent5c54a609a9abe09a3c5dd235868893cec5a4c88a (diff)
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
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_pose.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c96
1 files changed, 96 insertions, 0 deletions
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;
}