Spline IK: support using both original scaling and volume preservation.
authorAlexander Gavrilov <angavrilov@gmail.com>
Tue, 7 May 2019 16:52:10 +0000 (19:52 +0300)
committerAlexander Gavrilov <angavrilov@gmail.com>
Tue, 7 May 2019 16:54:36 +0000 (19:54 +0300)
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.

release/scripts/startup/bl_ui/properties_constraint.py
source/blender/blenkernel/intern/armature_update.c
source/blender/blenkernel/intern/constraint.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesrna/intern/rna_constraint.c

index fec90fe..f5b36d6 100644 (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()
index c71c2dc..97326fa 100644 (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... */
-    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. */
index 282847f..2ccfcf4 100644 (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)
index d3165ef..3abd5b4 100644 (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 */
index 49c1fa7..ef3ea19 100644 (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);