From 37eb1090148057e9c1ecaae6a94bf97c8e51dd61 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 7 May 2019 19:52:10 +0300 Subject: Spline IK: support using both original scaling and volume preservation. Add a new option that makes the Spline IK solver apply volume preservation on top of the original scaling, considering the pre-IK scale of the bone as the goal volume to be preserved. This basically works similar to the Stretch To constraint, and allows easily rigging a stretchy chain that uniformly follows its parent's scaling. Since the Stretch To behavior is more familiar, the new option is on by default for newly created Spline IK constraints. --- .../scripts/startup/bl_ui/properties_constraint.py | 3 ++ source/blender/blenkernel/intern/armature_update.c | 56 ++++++++++++---------- source/blender/blenkernel/intern/constraint.c | 1 + source/blender/makesdna/DNA_constraint_types.h | 3 ++ source/blender/makesrna/intern/rna_constraint.c | 7 +++ 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index fec90fef590..f5b36d6cfd0 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -801,6 +801,9 @@ class ConstraintButtonsPanel: layout.prop(con, "y_scale_mode") layout.prop(con, "xz_scale_mode") + if con.xz_scale_mode in {'INVERSE_PRESERVE', 'VOLUME_PRESERVE'}: + layout.prop(con, "use_original_scale") + if con.xz_scale_mode == 'VOLUME_PRESERVE': layout.prop(con, "bulge", text="Volume Variation") split = layout.split() diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index c71c2dc86cf..97326fa78f2 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -273,11 +273,12 @@ static void splineik_evaluate_bone( /* first, adjust the point positions on the curve */ float curveLen = tree->points[index] - tree->points[index + 1]; float pointStart = state->curve_position; + float poseScale = len_v3v3(poseHead, poseTail) / pchan->bone->length; 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; + baseScale = poseScale; } float pointEnd = pointStart + curveLen * baseScale * state->curve_scale; @@ -394,24 +395,31 @@ static void splineik_evaluate_bone( } /* step 4: set the scaling factors for the axes */ - { - /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ - mul_v3_fl(poseMat[1], scaleFac); - /* set the scaling factors of the x and z axes from... */ - switch (ikData->xzScaleMode) { - case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: { - /* original scales get used */ - float scale; + /* Always multiply the y-axis by the scaling factor to get the correct length. */ + mul_v3_fl(poseMat[1], scaleFac); + + /* After that, apply x/z scaling modes. */ + if (ikData->xzScaleMode != CONSTRAINT_SPLINEIK_XZS_NONE) { + /* First, apply the original scale if enabled. */ + if (ikData->xzScaleMode == CONSTRAINT_SPLINEIK_XZS_ORIGINAL || + (ikData->flag & CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE) != 0) { + float scale; + + /* x-axis scale */ + scale = len_v3(pchan->pose_mat[0]); + mul_v3_fl(poseMat[0], scale); + /* z-axis scale */ + scale = len_v3(pchan->pose_mat[2]); + mul_v3_fl(poseMat[2], scale); + + /* Adjust the scale factor used for volume preservation + * to consider the pre-IK scaling as the initial volume. */ + scaleFac /= poseScale; + } - /* x-axis scale */ - scale = len_v3(pchan->pose_mat[0]); - mul_v3_fl(poseMat[0], scale); - /* z-axis scale */ - scale = len_v3(pchan->pose_mat[2]); - mul_v3_fl(poseMat[2], scale); - break; - } + /* Apply volume preservation. */ + switch (ikData->xzScaleMode) { case CONSTRAINT_SPLINEIK_XZS_INVERSE: { /* old 'volume preservation' method using the inverse scale */ float scale; @@ -483,14 +491,14 @@ static void splineik_evaluate_bone( break; } } + } - /* finally, multiply the x and z scaling by the radius of the curve too, - * to allow automatic scales to get tweaked still - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { - mul_v3_fl(poseMat[0], radius); - mul_v3_fl(poseMat[2], radius); - } + /* Finally, multiply the x and z scaling by the radius of the curve too, + * to allow automatic scales to get tweaked still. + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { + mul_v3_fl(poseMat[0], radius); + mul_v3_fl(poseMat[2], radius); } /* Blend the scaling of the matrix according to the influence. */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 282847fe220..2ccfcf45e46 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4235,6 +4235,7 @@ static void splineik_new_data(void *cdata) data->bulge_min = 1.0f; data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; + data->flag = CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE; } static void splineik_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index d3165efb647..3abd5b4456e 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -906,6 +906,9 @@ typedef enum eSplineIK_Flags { /* for "volumetric" xz scale mode, limit the minimum or maximum scale values */ CONSTRAINT_SPLINEIK_USE_BULGE_MIN = (1 << 5), CONSTRAINT_SPLINEIK_USE_BULGE_MAX = (1 << 6), + + /* apply volume preservation over original scaling of the bone */ + CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE = (1 << 7), } eSplineIK_Flags; /* bSplineIKConstraint->xzScaleMode */ diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 49c1fa779ab..ef3ea19fa57 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -2604,6 +2604,13 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) "on top of the shape and scaling of the curve itself"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* take original scaling of the bone into account in volume preservation */ + prop = RNA_def_property(srna, "use_original_scale", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE); + RNA_def_property_ui_text( + prop, "Use Original Scale", "Apply volume preservation over the original scaling"); + 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