[Bf-blender-cvs] [cf2baa585cc] master: Fix T81707: Spline IK Joints "Floating" above curve

Sebastian Parborg noreply at git.blender.org
Thu Apr 8 15:52:39 CEST 2021


Commit: cf2baa585cc8788b29147d6e34fa8c46609e5bf9
Author: Sebastian Parborg
Date:   Thu Apr 8 15:51:08 2021 +0200
Branches: master
https://developer.blender.org/rBcf2baa585cc8788b29147d6e34fa8c46609e5bf9

Fix T81707: Spline IK Joints "Floating" above curve

The issue was that where_on_path uses a resampled curve to get the data
from the curve. This leads to disconnects between the curve the user
sees and the evaluated location data.

To fix this we simply use the actual curve data the user can see.

The older code needed a cleanup either way as there were hacks in other
parts of the code trying to work around some brokenness. This is now
fixed and we no longer need to clamp the evaluation range to 0-1 or make
helper functions to make it do what we actually want.

Reviewed By: Campbell, Sybren

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

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

M	source/blender/blenkernel/BKE_anim_path.h
M	source/blender/blenkernel/BKE_curve.h
M	source/blender/blenkernel/intern/anim_path.c
M	source/blender/blenkernel/intern/armature_update.c
M	source/blender/blenkernel/intern/constraint.c
M	source/blender/blenkernel/intern/curve_deform.c
M	source/blender/blenkernel/intern/displist.c
M	source/blender/blenkernel/intern/effect.c
M	source/blender/blenkernel/intern/font.c
M	source/blender/blenkernel/intern/object.c
M	source/blender/blenkernel/intern/particle.c
M	source/blender/draw/engines/overlay/overlay_extra.c
M	source/blender/editors/object/object_relations.c
M	source/blender/makesdna/DNA_curve_types.h
M	source/blender/makesrna/intern/rna_constraint.c
M	source/blender/modifiers/intern/MOD_array.c

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

diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h
index ae2d13530ed..9db63080fd9 100644
--- a/source/blender/blenkernel/BKE_anim_path.h
+++ b/source/blender/blenkernel/BKE_anim_path.h
@@ -26,22 +26,28 @@
 extern "C" {
 #endif
 
-struct ListBase;
+struct CurveCache;
 struct Object;
-struct Path;
 
 /* ---------------------------------------------------- */
 /* Curve Paths */
 
-void free_path(struct Path *path);
-void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
-bool where_on_path(const struct Object *ob,
-                   float ctime,
-                   float r_vec[4],
-                   float r_dir[3],
-                   float r_quat[4],
-                   float *r_radius,
-                   float *r_weight);
+int BKE_anim_path_get_array_size(const struct CurveCache *curve_cache);
+float BKE_anim_path_get_length(const struct CurveCache *curve_cache);
+
+/* This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
+ * You should never have to call this manually as it should already have been called by
+ * 'BKE_displist_make_curveTypes'. Do not call this manually unless you know what you are doing.
+ */
+void BKE_anim_path_calc_data(struct Object *ob);
+
+bool BKE_where_on_path(const struct Object *ob,
+                       float ctime,
+                       float r_vec[4],
+                       float r_dir[3],
+                       float r_quat[4],
+                       float *r_radius,
+                       float *r_weight);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 8381f015bee..26c9bef7d6c 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -50,7 +50,14 @@ typedef struct CurveCache {
   ListBase disp;
   ListBase bev;
   ListBase deformed_nurbs;
-  struct Path *path;
+  /* This array contains the accumulative length of the curve segments.
+   * So you can see this as a "total distance traveled" along the curve.
+   * The first entry is the length between point 0 and 1 while the last is the
+   * total length of the curve.
+   *
+   * Used by 'BKE_where_on_path'.
+   */
+  float *anim_path_accum_length;
 } CurveCache;
 
 /* Definitions needed for shape keys */
diff --git a/source/blender/blenkernel/intern/anim_path.c b/source/blender/blenkernel/intern/anim_path.c
index 628e54971ce..58ab5609fce 100644
--- a/source/blender/blenkernel/intern/anim_path.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -42,157 +42,193 @@ static CLG_LogRef LOG = {"bke.anim"};
 /* ******************************************************************** */
 /* Curve Paths - for curve deforms and/or curve following */
 
-/**
- * Free curve path data
- *
- * \note Frees the path itself!
- * \note This is increasingly inaccurate with non-uniform #BevPoint subdivisions T24633.
- */
-void free_path(Path *path)
+static int get_bevlist_seg_array_size(const BevList *bl)
 {
-  if (path->data) {
-    MEM_freeN(path->data);
+  if (bl->poly >= 0) {
+    /* Cyclic curve. */
+    return bl->nr;
   }
-  MEM_freeN(path);
+
+  return bl->nr - 1;
 }
 
-/**
- * Calculate a curve-deform path for a curve
- * - Only called from displist.c -> #do_makeDispListCurveTypes
- */
-void calc_curvepath(Object *ob, ListBase *nurbs)
+int BKE_anim_path_get_array_size(const CurveCache *curve_cache)
+{
+  BLI_assert(curve_cache != NULL);
+
+  BevList *bl = curve_cache->bev.first;
+
+  BLI_assert(bl != NULL && bl->nr > 1);
+
+  return get_bevlist_seg_array_size(bl);
+}
+
+float BKE_anim_path_get_length(const CurveCache *curve_cache)
 {
-  BevList *bl;
-  BevPoint *bevp, *bevpn, *bevpfirst, *bevplast;
-  PathPoint *pp;
-  Nurb *nu;
-  Path *path;
-  float *fp, *dist, *maxdist, xyz[3];
-  float fac, d = 0, fac1, fac2;
-  int a, tot, cycl = 0;
-
-  /* in a path vertices are with equal differences: path->len = number of verts */
-  /* NOW WITH BEVELCURVE!!! */
+  int seg_size = BKE_anim_path_get_array_size(curve_cache);
+  return curve_cache->anim_path_accum_length[seg_size - 1];
+}
 
+void BKE_anim_path_calc_data(struct Object *ob)
+{
   if (ob == NULL || ob->type != OB_CURVE) {
     return;
   }
-
-  if (ob->runtime.curve_cache->path) {
-    free_path(ob->runtime.curve_cache->path);
+  if (ob->runtime.curve_cache == NULL) {
+    CLOG_WARN(&LOG, "No curve cache!");
+    return;
   }
-  ob->runtime.curve_cache->path = NULL;
-
-  /* weak! can only use first curve */
-  bl = ob->runtime.curve_cache->bev.first;
+  /* We only use the first curve. */
+  BevList *bl = ob->runtime.curve_cache->bev.first;
   if (bl == NULL || !bl->nr) {
+    CLOG_WARN(&LOG, "No bev list data!");
     return;
   }
 
-  nu = nurbs->first;
-
-  ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
-
-  /* if POLY: last vertice != first vertice */
-  cycl = (bl->poly != -1);
+  /* Free old data. */
+  if (ob->runtime.curve_cache->anim_path_accum_length) {
+    MEM_freeN(ob->runtime.curve_cache->anim_path_accum_length);
+  }
 
-  tot = cycl ? bl->nr : bl->nr - 1;
+  /* We assume that we have at least two points.
+   * If there is less than two points in the curve,
+   * no BevList should have been generated.
+   */
+  BLI_assert(bl->nr > 1);
+
+  int seg_size = get_bevlist_seg_array_size(bl);
+
+  ob->runtime.curve_cache->anim_path_accum_length = (float *)MEM_mallocN(sizeof(float) * seg_size,
+                                                                         "calcpathdist");
+  float *len_data = ob->runtime.curve_cache->anim_path_accum_length;
+  BevPoint *bp_arr = bl->bevpoints;
+  float prev_len = 0.0f;
+  for (int i = 0; i < bl->nr - 1; i++) {
+    prev_len += len_v3v3(bp_arr[i].vec, bp_arr[i + 1].vec);
+    len_data[i] = prev_len;
+  }
 
-  path->len = tot + 1;
-  /* Exception: vector handle paths and polygon paths should be subdivided
-   * at least a factor resolution. */
-  if (path->len < nu->resolu * SEGMENTSU(nu)) {
-    path->len = nu->resolu * SEGMENTSU(nu);
+  if (bl->poly >= 0) {
+    /* Cyclic curve. */
+    len_data[seg_size - 1] = prev_len + len_v3v3(bp_arr[0].vec, bp_arr[bl->nr - 1].vec);
   }
+}
+
+static void get_curve_points_from_idx(const int idx,
+                                      BevList *bl,
+                                      bool is_cyclic,
+                                      BevPoint **r_p0,
+                                      BevPoint **r_p1,
+                                      BevPoint **r_p2,
+                                      BevPoint **r_p3)
+{
+  BLI_assert(idx >= 0);
+  BLI_assert(idx < bl->nr - 1 || (is_cyclic && idx < bl->nr));
+  BLI_assert(bl->nr > 1);
 
-  dist = (float *)MEM_mallocN(sizeof(float) * (tot + 1), "calcpathdist");
+  BevPoint *bp_arr = bl->bevpoints;
 
-  /* all lengths in *dist */
-  bevp = bevpfirst = bl->bevpoints;
-  fp = dist;
-  *fp = 0.0f;
-  for (a = 0; a < tot; a++) {
-    fp++;
-    if (cycl && a == tot - 1) {
-      sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec);
+  /* First segement. */
+  if (idx == 0) {
+    *r_p1 = &bp_arr[0];
+    if (is_cyclic) {
+      *r_p0 = &bp_arr[bl->nr - 1];
     }
     else {
-      sub_v3_v3v3(xyz, (bevp + 1)->vec, bevp->vec);
+      *r_p0 = *r_p1;
     }
 
-    *fp = *(fp - 1) + len_v3(xyz);
-    bevp++;
-  }
-
-  path->totdist = *fp;
-
-  /* the path verts  in path->data */
-  /* now also with TILT value */
-  pp = path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint) * path->len, "pathdata");
+    *r_p2 = &bp_arr[1];
 
-  bevp = bevpfirst;
-  bevpn = bevp + 1;
-  bevplast = bevpfirst + (bl->nr - 1);
-  if (UNLIKELY(bevpn > bevplast)) {
-    bevpn = cycl ? bevpfirst : bevplast;
-  }
-  fp = dist + 1;
-  maxdist = dist + tot;
-  fac = 1.0f / ((float)path->len - 1.0f);
-  fac = fac * path->totdist;
-
-  for (a = 0; a < path->len; a++) {
-
-    d = ((float)a) * fac;
-
-    /* we're looking for location (distance) 'd' in the array */
-    if (LIKELY(tot > 0)) {
-      while ((fp < maxdist) && (d >= *fp)) {
-        fp++;
-        if (bevp < bevplast) {
-          bevp++;
-        }
-        bevpn = bevp + 1;
-        if (UNLIKELY(bevpn > bevplast)) {
-          bevpn = cycl ? bevpfirst : bevplast;
-        }
-      }
-
-      fac1 = (*(fp)-d) / (*(fp) - *(fp - 1));
-      fac2 = 1.0f - fac1;
+    if (bl->nr > 2) {
+      *r_p3 = &bp_arr[2];
     }
     else {
-      fac1 = 1.0f;
-      fac2 = 0.0f;
+      *r_p3 = *r_p2;
     }
+    return;
+  }
 
-    interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2);
-    pp->vec[3] = fac1 * bevp->tilt + fac2 * bevpn->tilt;
-    pp->radius = fac1 * bevp->radius + fac2 * bevpn->radius;
-    pp->weight = fac1 * bevp->weight + fac2 * bevpn->weight;
-    interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2);
-    normalize_qt(pp->quat);
+  /* Last segment (or next to last in a cyclic curve). */
+  if (idx == bl->nr - 2) {
+    /* The case when the bl->nr == 2 falls in to the "first segement" check above.
+     * So here we can assume that bl->nr > 2.
+     */
+    *r_p0 = &bp_arr[idx - 1];
+    *r_p1 = &bp_arr[idx];
+    *r_p2 = &bp_arr[idx + 1];
+
+    if (is_cyclic) {
+      *r_p3 = &bp_arr[0];
+    }
+    else {
+      *r_p3 = *r_p2;
+    }
+    return;
+  }
 
-    pp++;
+  if (idx == bl->nr - 1) {
+    /* Last segment in a cyclic curve. This should only trigger if the curve is cyclic
+     * as it gets an extra segment between the end and the start point. */
+    *r_p0 = &bp_arr[idx - 1];
+    *r_p1 = &bp_arr[idx];
+    *r_p2 = &bp_arr[0];
+    *r_p3 = &bp_arr[1];
+    return;
   }
 
-  MEM_freeN(dist);
+  /* To get here the curve has to have four curve points or more and idx can't
+   * be the first or the last segment.
+   * So we can assume that we can get four points without any special checks.
+   */
+  *r_p0 = &bp_arr[idx - 1];
+  *r_p1 = &bp_arr[idx];
+  *r_p2 = &bp_arr[idx + 1];
+  *r_p3 = &bp_arr[idx + 2];
 }
 
-static int interval_test(const int min, const int max, int p1, const int cycl)
+static bool binary_search_anim_path(const float *accum_len_arr,
+                                    const int seg_size,
+                                    const float goal_len,
+                                    int *r

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list