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:
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c105
-rw-r--r--source/blender/makesdna/DNA_brush_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c1
4 files changed, 92 insertions, 17 deletions
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 26ffd1bbfef..1e52349a942 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -239,7 +239,7 @@ typedef struct SculptPoseIKChainSegment {
float initial_orig[3];
float initial_head[3];
float len;
- float scale;
+ float scale[3];
float rot[4];
float *weights;
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 56ba15bef70..a4a87051e03 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -146,14 +146,14 @@ static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float
}
}
-static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale)
+static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale[3])
{
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;
+ copy_v3_v3(segments[i].scale, scale);
}
}
@@ -645,9 +645,10 @@ static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain,
}
copy_v3_v3(ik_chain->segments[i].orig, origin);
copy_v3_v3(ik_chain->segments[i].initial_orig, origin);
+ copy_v3_v3(ik_chain->segments[i].head, head);
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;
+ copy_v3_fl(ik_chain->segments[i].scale, 1.0f);
}
}
@@ -656,7 +657,9 @@ 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) {
+ if (ELEM(brush->pose_deform_type,
+ BRUSH_POSE_DEFORM_SCALE_TRASLATE,
+ BRUSH_POSE_DEFORM_SQUASH_STRETCH)) {
return 1;
}
return brush->pose_ik_segments;
@@ -987,6 +990,19 @@ static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush)
pose_solve_translate_chain(ik_chain, ss->cache->grab_delta);
}
+/* Calculate a scale factor based on the grab delta. */
+static float sculpt_pose_get_scale_from_grab_delta(SculptSession *ss, const float ik_target[3])
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+ 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;
+ return segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane));
+}
+
static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush)
{
float ik_target[3];
@@ -998,14 +1014,8 @@ static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush)
/* 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));
+ float scale[3];
+ copy_v3_fl(scale, sculpt_pose_get_scale_from_grab_delta(ss, ik_target));
/* Write the scale into the segments. */
pose_solve_scale_chain(ik_chain, scale);
@@ -1055,6 +1065,45 @@ static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brus
}
}
+static void sculpt_pose_do_squash_stretch_deform(SculptSession *ss, Brush *UNUSED(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);
+
+ float scale[3];
+ scale[2] = sculpt_pose_get_scale_from_grab_delta(ss, ik_target);
+ scale[0] = scale[1] = sqrtf(1.0f / scale[2]);
+
+ /* Write the scale into the segments. */
+ pose_solve_scale_chain(ik_chain, scale);
+}
+
+static void sculpt_pose_align_pivot_local_space(float r_mat[4][4],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symm_area,
+ SculptPoseIKChainSegment *segment,
+ const float grab_location[3])
+{
+ float segment_origin_head[3];
+ float symm_head[3];
+ float symm_orig[3];
+
+ copy_v3_v3(symm_head, segment->head);
+ copy_v3_v3(symm_orig, segment->orig);
+
+ SCULPT_flip_v3_by_symm_area(symm_head, symm, symm_area, grab_location);
+ SCULPT_flip_v3_by_symm_area(symm_orig, symm, symm_area, grab_location);
+
+ sub_v3_v3v3(segment_origin_head, symm_head, symm_orig);
+ normalize_v3(segment_origin_head);
+
+ copy_v3_v3(r_mat[2], segment_origin_head);
+ ortho_basis_v3v3_v3(r_mat[0], r_mat[1], r_mat[2]);
+}
+
/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
@@ -1077,6 +1126,9 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
case BRUSH_POSE_DEFORM_SCALE_TRASLATE:
sculpt_pose_do_scale_translate_deform(ss, brush);
break;
+ case BRUSH_POSE_DEFORM_SQUASH_STRETCH:
+ sculpt_pose_do_squash_stretch_deform(ss, brush);
+ break;
}
/* Flip the segment chain in all symmetry axis and calculate the transform matrices for each
@@ -1101,17 +1153,38 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SCULPT_flip_v3_by_symm_area(
symm_initial_orig, symm, symm_area, ss->cache->orig_grab_location);
- /* 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);
+ float pivot_local_space[4][4];
+ unit_m4(pivot_local_space);
+
+ /* Align the segment pivot local space to the Z axis. */
+ if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SQUASH_STRETCH) {
+ sculpt_pose_align_pivot_local_space(pivot_local_space,
+ symm,
+ symm_area,
+ &ik_chain->segments[i],
+ ss->cache->orig_grab_location);
+ unit_m4(ik_chain->segments[i].trans_mat[symm_it]);
+ }
+ else {
+ quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot);
+ }
+
+ /* Apply segement scale to the transform. */
+ for (int scale_i = 0; scale_i < 3; scale_i++) {
+ mul_v3_fl(ik_chain->segments[i].trans_mat[symm_it][scale_i],
+ ik_chain->segments[i].scale[scale_i]);
+ }
translate_m4(ik_chain->segments[i].trans_mat[symm_it],
symm_orig[0] - symm_initial_orig[0],
symm_orig[1] - symm_initial_orig[1],
symm_orig[2] - symm_initial_orig[2]);
+
+ unit_m4(ik_chain->segments[i].pivot_mat[symm_it]);
translate_m4(
ik_chain->segments[i].pivot_mat[symm_it], symm_orig[0], symm_orig[1], symm_orig[2]);
+ mul_m4_m4_post(ik_chain->segments[i].pivot_mat[symm_it], pivot_local_space);
+
invert_m4_m4(ik_chain->segments[i].pivot_mat_inv[symm_it],
ik_chain->segments[i].pivot_mat[symm_it]);
}
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index be7c894b4e4..7490dbe5cdc 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -334,6 +334,7 @@ typedef enum eBrushClothForceFalloffType {
typedef enum eBrushPoseDeformType {
BRUSH_POSE_DEFORM_ROTATE_TWIST = 0,
BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1,
+ BRUSH_POSE_DEFORM_SQUASH_STRETCH = 2,
} eBrushPoseDeformType;
typedef enum eBrushPoseOriginType {
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 209e5a1ff8b..cc5cd97a8a0 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1963,6 +1963,7 @@ static void rna_def_brush(BlenderRNA *brna)
static const EnumPropertyItem brush_pose_deform_type_items[] = {
{BRUSH_POSE_DEFORM_ROTATE_TWIST, "ROTATE_TWIST", 0, "Rotate/Twist", ""},
{BRUSH_POSE_DEFORM_SCALE_TRASLATE, "SCALE_TRANSLATE", 0, "Scale/Translate", ""},
+ {BRUSH_POSE_DEFORM_SQUASH_STRETCH, "SQUASH_STRETCH", 0, "Squash/Stretch", ""},
{0, NULL, 0, NULL, NULL},
};