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.
This commit is contained in:
Alexander Gavrilov 2019-05-07 19:52:10 +03:00
parent b1a7711718
commit 37eb109014
5 changed files with 46 additions and 24 deletions

View File

@ -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()

View File

@ -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... */
/* 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;
}
/* Apply volume preservation. */
switch (ikData->xzScaleMode) {
case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: {
/* original scales get used */
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);
break;
}
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. */

View File

@ -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)

View File

@ -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 */

View File

@ -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);