[Bf-blender-cvs] [b0271e4f058] blender-v2.93-release: Fix T88065: Spline-IK bone position calculation fails in some cases

Sebastian Parborg noreply at git.blender.org
Thu May 6 19:02:22 CEST 2021


Commit: b0271e4f0582563d2ec72324a9f4eba1da1f6978
Author: Sebastian Parborg
Date:   Thu May 6 18:55:22 2021 +0200
Branches: blender-v2.93-release
https://developer.blender.org/rBb0271e4f0582563d2ec72324a9f4eba1da1f6978

Fix T88065: Spline-IK bone position calculation fails in some cases

Fix trying to use cross product on parallel vectors.

Fix intersection checks failing because we run into floating point
issues with very small numbers.

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

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 94c2755d4c6..4504f10967c 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -340,13 +340,22 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
   float isect_1[3], isect_2[3];
 
   /* Calculate the intersection point. */
-  isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
+  int ret = isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
 
-  /* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
-   * intersection point we want. And it will always intersect as we go from inside to outside
-   * of the sphere.
-   */
-  copy_v3_v3(r_tail_pos, isect_1);
+  if (ret > 0) {
+    /* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
+     * intersection point we want. And it will always intersect as we go from inside to outside
+     * of the sphere.
+     */
+    copy_v3_v3(r_tail_pos, isect_1);
+  }
+  else {
+    /* Couldn't find an intersection point. This means that the floating point
+     * values are too small and thus the intersection check fails.
+     * So assume that the distance is so small that tail_pos == head_pos.
+     */
+    copy_v3_v3(r_tail_pos, head_pos);
+  }
 
   cur_seg_idx = bp_idx - 2;
   float prev_seg_len = 0;
@@ -360,7 +369,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
   }
 
   /* Convert the point back into the 0-1 interpolation range. */
-  const float isect_seg_len = len_v3v3(prev_bp->vec, isect_1);
+  const float isect_seg_len = len_v3v3(prev_bp->vec, r_tail_pos);
   const float frac = isect_seg_len / len_v3v3(prev_bp->vec, bp->vec);
   *r_new_curve_pos = (prev_seg_len + isect_seg_len) / spline_len;
 
@@ -380,7 +389,7 @@ static void splineik_evaluate_bone(
 {
   bSplineIKConstraint *ik_data = tree->ik_data;
 
-  if (pchan->bone->length == 0.0f) {
+  if (pchan->bone->length < FLT_EPSILON) {
     /* Only move the bone position with zero length bones. */
     float bone_pos[4], dir[3], rad;
     BKE_where_on_path(ik_data->tar, state->curve_position, bone_pos, dir, NULL, &rad, NULL);
@@ -516,6 +525,25 @@ static void splineik_evaluate_bone(
      */
     cross_v3_v3v3(raxis, rmat[1], spline_vec);
 
+    /* Check if the old and new bone direction is parallel to each other.
+     * If they are, then 'raxis' should be near zero and we will have to get the rotation axis in
+     * some other way.
+     */
+    float norm = normalize_v3(raxis);
+
+    if (norm < FLT_EPSILON) {
+      /* Can't use cross product! */
+      int order[3] = {0, 1, 2};
+      float tmp_axis[3];
+      zero_v3(tmp_axis);
+
+      axis_sort_v3(spline_vec, order);
+
+      /* Use the second largest axis as the basis for the rotation axis. */
+      tmp_axis[order[1]] = 1.0f;
+      cross_v3_v3v3(raxis, tmp_axis, spline_vec);
+    }
+
     rangle = dot_v3v3(rmat[1], spline_vec);
     CLAMP(rangle, -1.0f, 1.0f);
     rangle = acosf(rangle);



More information about the Bf-blender-cvs mailing list