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--release/scripts/startup/bl_ui/properties_paint_common.py4
-rw-r--r--source/blender/blenkernel/BKE_paint.h1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c150
-rw-r--r--source/blender/makesdna/DNA_brush_types.h8
-rw-r--r--source/blender/makesrna/intern/rna_brush.c11
5 files changed, 149 insertions, 25 deletions
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 92d421f63a8..dbe3ced04b3 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -619,10 +619,12 @@ def brush_settings(layout, context, brush, popover=False):
if brush.sculpt_tool == 'POSE':
layout.separator()
+ layout.prop(brush, "pose_deform_type")
layout.prop(brush, "pose_origin_type")
layout.prop(brush, "pose_offset")
layout.prop(brush, "pose_smooth_iterations")
- layout.prop(brush, "pose_ik_segments")
+ if brush.pose_deform_type == 'ROTATE_TWIST':
+ layout.prop(brush, "pose_ik_segments")
layout.prop(brush, "use_pose_ik_anchored")
layout.separator()
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index a7ece2e3167..ac292432acc 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -239,6 +239,7 @@ typedef struct SculptPoseIKChainSegment {
float initial_orig[3];
float initial_head[3];
float len;
+ float scale;
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 c7511dfc80f..b5e2652df7c 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))
@@ -600,7 +626,19 @@ 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,
@@ -629,7 +667,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,7 +727,9 @@ 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);
@@ -802,13 +843,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 +932,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 +948,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 +968,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],
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index c143c2a442a..2e449f10563 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -331,6 +331,11 @@ typedef enum eBrushClothForceFalloffType {
BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1,
} eBrushClothForceFalloffType;
+typedef enum eBrushPoseDeformType {
+ BRUSH_POSE_DEFORM_ROTATE_TWIST = 0,
+ BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1,
+} eBrushPoseDeformType;
+
typedef enum eBrushPoseOriginType {
BRUSH_POSE_ORIGIN_TOPOLOGY = 0,
BRUSH_POSE_ORIGIN_FACE_SETS = 1,
@@ -478,7 +483,7 @@ typedef struct Brush {
char gpencil_sculpt_tool;
/** Active grease pencil weight tool. */
char gpencil_weight_tool;
- char _pad1[6];
+ char _pad1[2];
float autosmooth_factor;
@@ -510,6 +515,7 @@ typedef struct Brush {
float elastic_deform_volume_preservation;
/* pose */
+ int pose_deform_type;
float pose_offset;
int pose_smooth_iterations;
int pose_ik_segments;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index d3b607fcb76..9e78eec9c25 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1960,6 +1960,12 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ 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", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem brush_pose_origin_type_items[] = {
{BRUSH_POSE_ORIGIN_TOPOLOGY,
"TOPOLOGY",
@@ -2095,6 +2101,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_deform_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_pose_deform_type_items);
+ RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "pose_origin_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, brush_pose_origin_type_items);
RNA_def_property_ui_text(prop,