[Bf-blender-cvs] [d851fc3ad67] master: Fix T77330, T81704: Spline IK doesn't preserve bone scale correctly

Sebastian Parborg noreply at git.blender.org
Tue Apr 13 19:46:07 CEST 2021


Commit: d851fc3ad6770a5634db8ca41aaa1267c7155245
Author: Sebastian Parborg
Date:   Tue Apr 13 19:18:48 2021 +0200
Branches: master
https://developer.blender.org/rBd851fc3ad6770a5634db8ca41aaa1267c7155245

Fix T77330, T81704: Spline IK doesn't preserve bone scale correctly

Previously, the bone position outside of "fit to curve length" mode was
incorrect.

It assumed that the curve was completely straight with no bends or
turns. This would lead to bones being scaled down as their final
position would be servery underestimated in some cases.

The solution is to do a sphere -> curve intersection test to see where
to put the bones while still preserving their length. As we are using
the tessellated curve data this essentially boils down to us doing a
sphere -> line intersection check.

Reviewed By: Sybren

Differential Revision: http://developer.blender.org/D10849

===================================================================

M	source/blender/blenkernel/intern/armature_update.c

===================================================================

diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 475b64cb9b3..9130c378121 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -63,40 +63,40 @@ typedef struct tSplineIK_Tree {
 
   bPoseChannel *root; /* bone that is the root node of the chain */
 
-  bConstraint *con;            /* constraint for this chain */
-  bSplineIKConstraint *ikData; /* constraint settings for this chain */
+  bConstraint *con;             /* constraint for this chain */
+  bSplineIKConstraint *ik_data; /* constraint settings for this chain */
 } tSplineIK_Tree;
 
 /* ----------- */
 
-/* Tag the bones in the chain formed by the given bone for IK */
+/* Tag the bones in the chain formed by the given bone for IK. */
 static void splineik_init_tree_from_pchan(Scene *UNUSED(scene),
                                           Object *UNUSED(ob),
                                           bPoseChannel *pchan_tip)
 {
-  bPoseChannel *pchan, *pchanRoot = NULL;
-  bPoseChannel *pchanChain[255];
+  bPoseChannel *pchan, *pchan_root = NULL;
+  bPoseChannel *pchan_chain[255];
   bConstraint *con = NULL;
-  bSplineIKConstraint *ikData = NULL;
-  float boneLengths[255];
-  float totLength = 0.0f;
+  bSplineIKConstraint *ik_data = NULL;
+  float bone_lengths[255];
+  float totlength = 0.0f;
   int segcount = 0;
 
-  /* find the SplineIK constraint */
+  /* Find the SplineIK constraint. */
   for (con = pchan_tip->constraints.first; con; con = con->next) {
     if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
-      ikData = con->data;
+      ik_data = con->data;
 
-      /* target can only be curve */
-      if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE)) {
+      /* Target can only be a curve. */
+      if ((ik_data->tar == NULL) || (ik_data->tar->type != OB_CURVE)) {
         continue;
       }
-      /* skip if disabled */
+      /* Skip if disabled. */
       if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))) {
         continue;
       }
 
-      /* otherwise, constraint is ok... */
+      /* Otherwise, constraint is ok... */
       break;
     }
   }
@@ -104,102 +104,102 @@ static void splineik_init_tree_from_pchan(Scene *UNUSED(scene),
     return;
   }
 
-  /* find the root bone and the chain of bones from the root to the tip
+  /* Find the root bone and the chain of bones from the root to the tip.
    * NOTE: this assumes that the bones are connected, but that may not be true... */
-  for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen);
+  for (pchan = pchan_tip; pchan && (segcount < ik_data->chainlen);
        pchan = pchan->parent, segcount++) {
-    /* store this segment in the chain */
-    pchanChain[segcount] = pchan;
+    /* Store this segment in the chain. */
+    pchan_chain[segcount] = pchan;
 
-    /* if performing rebinding, calculate the length of the bone */
-    boneLengths[segcount] = pchan->bone->length;
-    totLength += boneLengths[segcount];
+    /* If performing rebinding, calculate the length of the bone. */
+    bone_lengths[segcount] = pchan->bone->length;
+    totlength += bone_lengths[segcount];
   }
 
   if (segcount == 0) {
     return;
   }
 
-  pchanRoot = pchanChain[segcount - 1];
+  pchan_root = pchan_chain[segcount - 1];
 
-  /* perform binding step if required */
-  if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
+  /* Perform binding step if required. */
+  if ((ik_data->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
     float segmentLen = (1.0f / (float)segcount);
 
-    /* setup new empty array for the points list */
-    if (ikData->points) {
-      MEM_freeN(ikData->points);
+    /* Setup new empty array for the points list. */
+    if (ik_data->points) {
+      MEM_freeN(ik_data->points);
     }
-    ikData->numpoints = ikData->chainlen + 1;
-    ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
+    ik_data->numpoints = ik_data->chainlen + 1;
+    ik_data->points = MEM_mallocN(sizeof(float) * ik_data->numpoints, "Spline IK Binding");
 
-    /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
-    ikData->points[0] = 1.0f;
+    /* Bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint). */
+    ik_data->points[0] = 1.0f;
 
-    /* perform binding of the joints to parametric positions along the curve based
-     * proportion of the total length that each bone occupies
+    /* Perform binding of the joints to parametric positions along the curve based
+     * proportion of the total length that each bone occupies.
      */
     for (int i = 0; i < segcount; i++) {
-      /* 'head' joints, traveling towards the root of the chain
-       * - 2 methods; the one chosen depends on whether we've got usable lengths
+      /* 'head' joints, traveling towards the root of the chain.
+       * - 2 methods; the one chosen depends on whether we've got usable lengths.
        */
-      if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
-        /* 1) equi-spaced joints */
-        ikData->points[i + 1] = ikData->points[i] - segmentLen;
+      if ((ik_data->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totlength == 0.0f)) {
+        /* 1) Equi-spaced joints. */
+        ik_data->points[i + 1] = ik_data->points[i] - segmentLen;
       }
       else {
-        /* 2) to find this point on the curve, we take a step from the previous joint
-         *    a distance given by the proportion that this bone takes
+        /* 2) To find this point on the curve, we take a step from the previous joint
+         *    a distance given by the proportion that this bone takes.
          */
-        ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
+        ik_data->points[i + 1] = ik_data->points[i] - (bone_lengths[i] / totlength);
       }
     }
 
-    /* spline has now been bound */
-    ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
+    /* Spline has now been bound. */
+    ik_data->flag |= CONSTRAINT_SPLINEIK_BOUND;
   }
 
-  /* disallow negative values (happens with float precision) */
-  CLAMP_MIN(ikData->points[segcount], 0.0f);
+  /* Disallow negative values (happens with float precision). */
+  CLAMP_MIN(ik_data->points[segcount], 0.0f);
 
-  /* make a new Spline-IK chain, and store it in the IK chains */
+  /* Make a new Spline-IK chain, and store it in the IK chains. */
   /* TODO: we should check if there is already an IK chain on this,
    * since that would take precedence... */
   {
-    /* make new tree */
+    /* Make a new tree. */
     tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
     tree->type = CONSTRAINT_TYPE_SPLINEIK;
 
     tree->chainlen = segcount;
-    tree->totlength = totLength;
+    tree->totlength = totlength;
 
-    /* copy over the array of links to bones in the chain (from tip to root) */
+    /* Copy over the array of links to bones in the chain (from tip to root). */
     tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
-    memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
+    memcpy(tree->chain, pchan_chain, sizeof(bPoseChannel *) * segcount);
 
-    /* store reference to joint position array */
-    tree->points = ikData->points;
+    /* Store reference to joint position array. */
+    tree->points = ik_data->points;
 
-    /* store references to different parts of the chain */
-    tree->root = pchanRoot;
+    /* Store references to different parts of the chain. */
+    tree->root = pchan_root;
     tree->con = con;
-    tree->ikData = ikData;
+    tree->ik_data = ik_data;
 
-    /* AND! link the tree to the root */
-    BLI_addtail(&pchanRoot->siktree, tree);
+    /* AND! Link the tree to the root. */
+    BLI_addtail(&pchan_root->siktree, tree);
   }
 
-  /* mark root channel having an IK tree */
-  pchanRoot->flag |= POSE_IKSPLINE;
+  /* Mark root channel having an IK tree. */
+  pchan_root->flag |= POSE_IKSPLINE;
 }
 
-/* Tag which bones are members of Spline IK chains */
+/* Tag which bones are members of Spline IK chains. */
 static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
 {
   bPoseChannel *pchan;
 
-  /* find the tips of Spline IK chains,
-   * which are simply the bones which have been tagged as such */
+  /* Find the tips of Spline IK chains,
+   * which are simply the bones which have been tagged as such. */
   for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
     if (pchan->constflag & PCHAN_HAS_SPLINEIK) {
       splineik_init_tree_from_pchan(scene, ob, pchan);
@@ -213,21 +213,24 @@ typedef struct tSplineIk_EvalState {
   float curve_position;      /* Current position along the curve. */
   float curve_scale;         /* Global scale to apply to curve positions. */
   float locrot_offset[4][4]; /* Bone rotation and location offset inherited from parent. */
+  float prev_tail_loc[3];    /* Tail location of the previous bone. */
+  float prev_tail_radius;    /* Tail curve radius of the previous bone. */
+  int prev_tail_seg_idx;     /* Curve segment the previous tail bone belongs to. */
 } tSplineIk_EvalState;
 
 /* Prepare data to evaluate spline IK. */
 static bool splineik_evaluate_init(tSplineIK_Tree *tree, tSplineIk_EvalState *state)
 {
-  bSplineIKConstraint *ikData = tree->ikData;
+  bSplineIKConstraint *ik_data = tree->ik_data;
 
   /* Make sure that the constraint targets are ok, to avoid crashes
    * in case of a depsgraph bug or dependency cycle.
    */
-  if (ikData->tar == NULL) {
+  if (ik_data->tar == NULL) {
     return false;
   }
 
-  CurveCache *cache = ikData->tar->runtime.curve_cache;
+  CurveCache *cache = ik_data->tar->runtime.curve_cache;
 
   if (ELEM(NULL, cache, cache->anim_path_accum_length)) {
     return false;
@@ -237,97 +240,249 @@ static bool splineik_evaluate_init(tSplineIK_Tree *tree, tSplineIk_EvalState *st
   state->curve_position = 0.0f;
   state->curve_scale = 1.0f;
   unit_m4(state->locrot_offset);
+  zero_v3(state->prev_tail_loc);
+  state->prev_tail_radius = 1.0f;
+  state->prev_tail_seg_idx = 0;
 
   /* Ap

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list