diff options
author | YimingWu <xp8110@outlook.com> | 2020-05-30 11:34:11 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2020-05-30 11:34:11 +0300 |
commit | 3b52dfe549f0c2fca7e0cd499b85fb098e9b4da9 (patch) | |
tree | 668b6b25da0efdb87058b197084094181fb0c09f /source/blender/editors/sculpt_paint/sculpt_pose.c | |
parent | cd54abd2c1316136753f7bbe227bd762a5f9e7d9 (diff) | |
parent | 2ee94c954d6700a45fde320f330964bcf1888545 (diff) |
Merge remote-tracking branch 'origin/master' into temp-lanpr-review
# Conflicts:
# release/datafiles/locale
# release/scripts/addons
# source/blender/blenkernel/intern/lib_query.c
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_pose.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_pose.c | 175 |
1 files changed, 146 insertions, 29 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index c7511dfc80f..35f4870fa12 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -131,6 +131,32 @@ static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain, } } +static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float delta[3]) +{ + SculptPoseIKChainSegment *segments = ik_chain->segments; + const int tot_segments = ik_chain->tot_segments; + + for (int i = 0; i < tot_segments; i++) { + /* Move the origin and head of each segment by delta. */ + add_v3_v3v3(segments[i].head, segments[i].initial_head, delta); + add_v3_v3v3(segments[i].orig, segments[i].initial_orig, delta); + + /* Reset the segment rotation. */ + unit_qt(segments[i].rot); + } +} + +static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale) +{ + SculptPoseIKChainSegment *segments = ik_chain->segments; + const int tot_segments = ik_chain->tot_segments; + + for (int i = 0; i < tot_segments; i++) { + /* Assign the scale to each segment. */ + segments[i].scale = scale; + } +} + static void do_pose_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) @@ -363,10 +389,14 @@ typedef struct PoseFloodFillData { GSet *visited_face_sets; /* In face sets origin mode, each vertex can only be assigned to one face set. */ - bool *is_weighted; + BLI_bitmap *is_weighted; bool is_first_iteration; + /* In topology mode this stores the furthest point from the stroke origin for cases when a pose + * origin based on the brush radius can't be set. */ + float fallback_floodfill_origin[3]; + /* Fallback origin. If we can't find any face set to continue, use the position of all vertices * that have the current face set. */ float fallback_origin[3]; @@ -377,12 +407,17 @@ static bool pose_topology_floodfill_cb( SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; + const float *co = SCULPT_vertex_co_get(ss, to_v); if (data->pose_factor) { data->pose_factor[to_v] = 1.0f; } - const float *co = SCULPT_vertex_co_get(ss, to_v); + if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) < + len_squared_v3v3(data->pose_initial_co, co)) { + copy_v3_v3(data->fallback_floodfill_origin, co); + } + if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { return true; @@ -415,7 +450,7 @@ static bool pose_face_sets_floodfill_cb( if (data->current_face_set == SCULPT_FACE_SET_NONE) { data->pose_factor[index] = 1.0f; - data->is_weighted[index] = true; + BLI_BITMAP_ENABLE(data->is_weighted, index); if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { @@ -446,9 +481,9 @@ static bool pose_face_sets_floodfill_cb( if (is_vertex_valid) { - if (!data->is_weighted[index]) { + if (!BLI_BITMAP_TEST(data->is_weighted, index)) { data->pose_factor[index] = 1.0f; - data->is_weighted[index] = true; + BLI_BITMAP_ENABLE(data->is_weighted, index); visit_next = true; } @@ -521,12 +556,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd, }; zero_v3(fdata.pose_origin); copy_v3_v3(fdata.pose_initial_co, initial_location); + copy_v3_v3(fdata.fallback_floodfill_origin, initial_location); SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata); SCULPT_floodfill_free(&flood); if (fdata.tot_co > 0) { mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co); } + else { + copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin); + } /* Offset the pose origin. */ float pose_d[3]; @@ -600,9 +639,21 @@ static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain, copy_v3_v3(ik_chain->segments[i].initial_orig, origin); copy_v3_v3(ik_chain->segments[i].initial_head, head); ik_chain->segments[i].len = len_v3v3(head, origin); + ik_chain->segments[i].scale = 1.0f; } } +static int pose_brush_num_effective_segments(const Brush *brush) +{ + /* Scaling multiple segments at the same time is not supported as the IK solver can't handle + * changes in the segment's length. It will also required a better weight distribution to avoid + * artifacts in the areas affected by multiple segments. */ + if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SCALE_TRASLATE) { + return 1; + } + return brush->pose_ik_segments; +} + static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, Object *ob, SculptSession *ss, @@ -629,7 +680,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, pose_factor_grow[nearest_vertex_index] = 1.0f; - SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert); + const int tot_segments = pose_brush_num_effective_segments(br); + SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert); /* Calculate the first segment in the chain using the brush radius and the pose origin offset. */ copy_v3_v3(next_chain_segment_target, initial_location); @@ -688,11 +740,13 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( int totvert = SCULPT_vertex_count_get(ss); - SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert); + const int tot_segments = pose_brush_num_effective_segments(br); + + SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert); GSet *visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", ik_chain->tot_segments); - bool *is_weighted = MEM_callocN(sizeof(bool) * totvert, "weighted"); + BLI_bitmap *is_weighted = BLI_BITMAP_NEW(totvert, "weighted"); int current_face_set = SCULPT_FACE_SET_NONE; int prev_face_set = SCULPT_FACE_SET_NONE; @@ -802,13 +856,86 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br MEM_SAFE_FREE(nodes); } +static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush) +{ + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + BKE_curvemapping_initialize(brush->curve); + pose_solve_translate_chain(ik_chain, ss->cache->grab_delta); +} + +static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush) +{ + float ik_target[3]; + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + copy_v3_v3(ik_target, ss->cache->true_location); + add_v3_v3(ik_target, ss->cache->grab_delta); + + /* Solve the IK for the first segment to include rotation as part of scale. */ + pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); + + /* Calculate a scale factor based on the grab delta. */ + float plane[4]; + float segment_dir[3]; + sub_v3_v3v3(segment_dir, ik_chain->segments[0].initial_head, ik_chain->segments[0].initial_orig); + normalize_v3(segment_dir); + plane_from_point_normal_v3(plane, ik_chain->segments[0].initial_head, segment_dir); + const float segment_len = ik_chain->segments[0].len; + const float scale = segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane)); + + /* Write the scale into the segments. */ + pose_solve_scale_chain(ik_chain, scale); +} + +static void sculpt_pose_do_twist_deform(SculptSession *ss, Brush *brush) +{ + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + /* Calculate the maximum roll. 0.02 radians per pixel works fine. */ + float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * 0.02f; + BKE_curvemapping_initialize(brush->curve); + pose_solve_roll_chain(ik_chain, brush, roll); +} + +static void sculpt_pose_do_rotate_deform(SculptSession *ss, Brush *brush) +{ + float ik_target[3]; + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + /* Calculate the IK target. */ + copy_v3_v3(ik_target, ss->cache->true_location); + add_v3_v3(ik_target, ss->cache->grab_delta); + + /* Solve the IK positions. */ + pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); +} + +static void sculpt_pose_do_rotate_twist_deform(SculptSession *ss, Brush *brush) +{ + if (ss->cache->invert) { + sculpt_pose_do_twist_deform(ss, brush); + } + else { + sculpt_pose_do_rotate_deform(ss, brush); + } +} + +static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brush) +{ + if (ss->cache->invert) { + sculpt_pose_do_translate_deform(ss, brush); + } + else { + sculpt_pose_do_scale_deform(ss, brush); + } +} + /* Main Brush Function. */ void SCULPT_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]; - float ik_target[3]; const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; /* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be @@ -818,26 +945,15 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + copy_v3_v3(grab_delta, ss->cache->grab_delta); - /* Solve the positions and rotations of the IK chain. */ - if (ss->cache->invert) { - /* Roll Mode. */ - /* Calculate the maximum roll. 0.02 radians per pixel works fine. */ - float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * - 0.02f; - BKE_curvemapping_initialize(brush->curve); - pose_solve_roll_chain(ik_chain, brush, roll); - } - else { - /* IK follow target mode. */ - /* Calculate the IK target. */ - - copy_v3_v3(grab_delta, ss->cache->grab_delta); - copy_v3_v3(ik_target, ss->cache->true_location); - add_v3_v3(ik_target, ss->cache->grab_delta); - - /* Solve the IK positions. */ - pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); + switch (brush->pose_deform_type) { + case BRUSH_POSE_DEFORM_ROTATE_TWIST: + sculpt_pose_do_rotate_twist_deform(ss, brush); + break; + case BRUSH_POSE_DEFORM_SCALE_TRASLATE: + sculpt_pose_do_scale_translate_deform(ss, brush); + break; } /* Flip the segment chain in all symmetry axis and calculate the transform matrices for each @@ -845,7 +961,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* This can be optimized by skipping the calculation of matrices where the symmetry is not * enabled. */ for (int symm_it = 0; symm_it < PAINT_SYMM_AREAS; symm_it++) { - for (int i = 0; i < brush->pose_ik_segments; i++) { + for (int i = 0; i < ik_chain->tot_segments; i++) { float symm_rot[4]; float symm_orig[3]; float symm_initial_orig[3]; @@ -865,6 +981,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* Create the transform matrix and store it in the segment. */ unit_m4(ik_chain->segments[i].pivot_mat[symm_it]); quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot); + mul_m4_fl(ik_chain->segments[i].trans_mat[symm_it], ik_chain->segments[i].scale); translate_m4(ik_chain->segments[i].trans_mat[symm_it], symm_orig[0] - symm_initial_orig[0], |