From ad9275ed4e60b7ca4874bbb2c80fef6e2606eb39 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 15 Apr 2019 20:25:41 +0300 Subject: Spline IK: support changing individual bone length via Y scaling. Previously Spline IK provided only two choices: either scale the length of the bone chain to fit the length of the curve, or don't scale the bone in the Y dimension at all (ignoring effects of actually fitting to the curve due to curvature and curve object scale). This patch adds a new option to use the pre-IK Y scale of the bones to adjust their length when fitted to the curve, allowing individual posing control over the length of the segments. Reviewers: brecht Differential Revision: https://developer.blender.org/D4687 --- .../scripts/startup/bl_ui/properties_constraint.py | 2 +- source/blender/blenkernel/intern/armature_update.c | 8 +++++++- source/blender/blenkernel/intern/constraint.c | 2 ++ source/blender/blenloader/intern/versioning_280.c | 17 ++++++++++++++++ source/blender/makesdna/DNA_constraint_types.h | 15 ++++++++++++++ source/blender/makesrna/intern/rna_constraint.c | 23 +++++++++++++++++----- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index bf34e767f3a..0fc67d4aed6 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -794,9 +794,9 @@ class ConstraintButtonsPanel: col = layout.column() col.label(text="Chain Scaling:") - col.prop(con, "use_y_stretch") col.prop(con, "use_curve_radius") + layout.prop(con, "y_scale_mode") layout.prop(con, "xz_scale_mode") if con.xz_scale_mode == 'VOLUME_PRESERVE': diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index c76bf663b72..51333251b8e 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -230,7 +230,7 @@ static bool splineik_evaluate_init(tSplineIK_Tree *tree, tSplineIk_EvalState *st unit_m4(state->locrot_offset); /* Apply corrections for sensitivity to scaling. */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (tree->totlength != 0.0f)) { + if ((ikData->yScaleMode != CONSTRAINT_SPLINEIK_YS_FIT_CURVE) && (tree->totlength != 0.0f)) { /* get the current length of the curve */ /* NOTE: this is assumed to be correct even after the curve was resized */ float splineLen = cache->path->totdist; @@ -262,6 +262,12 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Object *ob, bPoseChanne float curveLen = tree->points[index] - tree->points[index + 1]; float pointStart = state->curve_position; float baseScale = 1.0f; + + if (ikData->yScaleMode == CONSTRAINT_SPLINEIK_YS_ORIGINAL) { + /* Carry over the bone Y scale to the curve range. */ + baseScale = len_v3v3(poseHead, poseTail) / pchan->bone->length; + } + float pointEnd = pointStart + curveLen * baseScale * state->curve_scale; state->curve_position = pointEnd; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c774e2ff157..1ba29424def 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3959,6 +3959,8 @@ static void splineik_new_data(void *cdata) data->bulge = 1.0; data->bulge_max = 1.0f; data->bulge_min = 1.0f; + + data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; } static void splineik_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 41b1627e873..528bfd2360f 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3140,6 +3140,23 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } { + if (!DNA_struct_elem_find(fd->filesdna, "bSplineIKConstraint", "short", "yScaleMode")) { + for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { + if (ob->pose) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (bConstraint *con = pchan->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SPLINEIK) { + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + if ((data->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) == 0) { + data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; + } + } + } + } + } + } + } + /* Versioning code until next subversion bump goes here. */ } } diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index a7e44bea149..9dbebee5c89 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -231,6 +231,9 @@ typedef struct bSplineIKConstraint { short flag; /** Method used for determining the x & z scaling of the bones. */ short xzScaleMode; + /** Method used for determining the y scaling of the bones. */ + short yScaleMode; + short _pad[3]; /* volume preservation settings */ float bulge; @@ -879,8 +882,10 @@ typedef enum eSplineIK_Flags { CONSTRAINT_SPLINEIK_BOUND = (1 << 0), /* root of chain is not influenced by the constraint */ CONSTRAINT_SPLINEIK_NO_ROOT = (1 << 1), +#ifdef DNA_DEPRECATED /* bones in the chain should not scale to fit the curve */ CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1 << 2), +#endif /* evenly distribute the bones along the path regardless of length */ CONSTRAINT_SPLINEIK_EVENSPLITS = (1 << 3), /* don't adjust the x and z scaling of the bones by the curve radius */ @@ -903,6 +908,16 @@ typedef enum eSplineIK_XZScaleModes { CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC = 3, } eSplineIK_XZScaleModes; +/* bSplineIKConstraint->yScaleMode */ +typedef enum eSplineIK_YScaleModes { + /* no y scaling */ + CONSTRAINT_SPLINEIK_YS_NONE = 0, + /* bones in the chain should be scaled to fit the length of the curve */ + CONSTRAINT_SPLINEIK_YS_FIT_CURVE = 1, + /* bones in the chain should take their y scales from the original scaling */ + CONSTRAINT_SPLINEIK_YS_ORIGINAL = 2, +} eSplineIK_YScaleModes; + /* bArmatureConstraint -> flag */ typedef enum eArmature_Flags { /** use dual quaternion blending */ diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index bd7f75f86b5..731e25b7e9a 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -2262,6 +2262,15 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem splineik_y_scale_mode[] = { + {CONSTRAINT_SPLINEIK_YS_NONE, "NONE", 0, "None", "Don't scale in the Y axis"}, + {CONSTRAINT_SPLINEIK_YS_FIT_CURVE, "FIT_CURVE", 0, "Fit Curve", + "Scale the bones to fit the entire length of the curve"}, + {CONSTRAINT_SPLINEIK_YS_ORIGINAL, "BONE_ORIGINAL", 0, "Bone Original", + "Use the original Y scale of the bone"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "SplineIKConstraint", "Constraint"); RNA_def_struct_ui_text(srna, "Spline IK Constraint", "Align 'n' bones along a curve"); RNA_def_struct_sdna_from(srna, "bSplineIKConstraint", "data"); @@ -2308,11 +2317,6 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) "Ignore the relative lengths of the bones when fitting to the curve"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - prop = RNA_def_property(srna, "use_y_stretch", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_SCALE_LIMITED); - RNA_def_property_ui_text(prop, "Y Stretch", "Stretch the Y axis of the bones to fit the curve"); - RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - prop = RNA_def_property(srna, "use_curve_radius", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_NO_CURVERAD); RNA_def_property_ui_text(prop, "Use Curve Radius", @@ -2328,6 +2332,15 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) "Method used for determining the scaling of the X and Z axes of the bones"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* y scaling mode */ + prop = RNA_def_property(srna, "y_scale_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "yScaleMode"); + RNA_def_property_enum_items(prop, splineik_y_scale_mode); + RNA_def_property_ui_text(prop, "Y Scale Mode", + "Method used for determining the scaling of the Y axis of the bones, " + "on top of the shape and scaling of the curve itself"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* volume presevation for "volumetric" scale mode */ prop = RNA_def_property(srna, "bulge", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 100.f); -- cgit v1.2.3