Page MenuHome

Fix T81707: Spline IK Joints "Floating" above curve
ClosedPublic

Authored by Sebastian Parborg (zeddb) on Apr 6 2021, 2:06 PM.

Details

Summary

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.

Before:

After:

Diff Detail

Event Timeline

Sebastian Parborg (zeddb) requested review of this revision.Apr 6 2021, 2:06 PM
Sebastian Parborg (zeddb) created this revision.

Nice to see this significantly improved, noted some minor issues inline and found a bug in binary search when testing.


With this file, in the 3D view press R, 10 to rotate 10 degrees.

source/blender/blenkernel/BKE_anim_path.h
34–44

Could use BKE_ convention for naming, but can be a separate commit too.

source/blender/blenkernel/BKE_curve.h
53–58

Can be const (as long as free calls cast to void *).

53–58

A short description of what this is would be good (lengths, first value always 0.0... it can be cyclic ... etc).

source/blender/blenkernel/intern/anim_path.c
45

Can be const.

309–342

The bisect lookup could be split into it's own static function.

314

I'd be wary of any nan values causing this to enter an eternal loop.
If nan values don't cause problems, a comment explaining why this isn't a concern.

Sebastian Parborg (zeddb) marked 3 inline comments as done.
Sebastian Parborg (zeddb) marked an inline comment as done and an inline comment as not done.Apr 6 2021, 7:27 PM
Sebastian Parborg (zeddb) added inline comments.
source/blender/blenkernel/BKE_curve.h
53–58

But it can't be const as we get new pointer addressees when allocating the array?

source/blender/blenkernel/intern/anim_path.c
309–342

I don't think that would be good.
The function would have to take around 9-10 arguments and I think that is messier than just having it in the rest of the main function like it is now.

314

I looked this over and noticed that I had implemented binary search wrong.
Now it will not get stuck in endless loops anymore and exit if it can't find a value.

This should never happen though, so I added a assert and a comment stating as much.

NaN shouldn't be an issue as we will automatically return if we run out of search space (cur_step == 0).

Do you think I have to comment this or is it clear for the code?

Sybren A. Stüvel (sybren) requested changes to this revision.Apr 8 2021, 12:33 PM
Sybren A. Stüvel (sybren) added inline comments.
source/blender/blenkernel/BKE_anim_path.h
35–45

These functions are now named BKE_{verb}_{submodule}_{noun}. I think it's more common to have BKE_{submodule}_{verb}_{noun} or `BKE_{submodule}_{noun}_{verb}, so that alphabetical ordering (like in IDE autocompletion) will group related functions together.

35–45

To me there is little difference between "length" and "total distance", so these names could be improved. I'm guessing that len indicates "number of segments in the curve" and tot_dist indicates "arc length of the curve", but "length" could just as well mean "arc length". Having "distance" as a name for "arc length" would be weird though, so my guess could be wrong.

source/blender/blenkernel/BKE_curve.h
53–58

typo

55–56

"distance" → "length" or "arc length". A distance is defined between two things, and is not a propery of a single thing.

58

"len_data" should be "the length of the data", f.e. the length of an array. anim_path_accum_length would be better.

source/blender/blenkernel/intern/anim_path.c
87–88

Why is this assumed?

143–144

typo

152–154

Here we are under a "last segment" comment in a "cyclic" condition, yet "Last segment in a cyclic curve" is handled below. This is confusing.

188

This is missing "and idx does not refer to the first or last segment".

258–261

That's clear from the code. Why is this enough, though?

266–269

I think this can be rewritten so that it can become a const. Assigning false and then conditionally assigning true simply means assigning the condition.

By renaming the variable to is_cyclic the comment can also be removed, as then the code is clear enough by itself. With all these rewrites, I don't see the benefit of keeping this cryptic name.

By comparing using >= 0 the "is non-negative" is clearer to me at first glance.

In other words: const bool is_cyclic = bl->poly >= 0.

279

const

281

const

285

const

286

const

298

p1 and p2 are already in use for the final result points. I'd just name them left_len and right_len so that they match a typical binary search. It also makes the relation cleare between these and the /* Go to the right. */ and /* Else, go to the left. */ comments.

300

Unnecessary parentheses.

301–305

Shouldn't this check appear either before cur_step is used, or after it has been assigned a new value? It's strange to have it here in the middle.

303

Unnecessary parentheses.

304

Change this to BLI_assert(!"Couldn't find any valid point on the animation path!") so that the assertion states the reason for it failling.

308–312

This "go to the next half" code is a bit strange. It seems to spread its code between this bit and the first line of the next loop iteration (cur_idx = cur_base + (cur_step / 2);).

A traditional binary search maintains an index of the left and right element of the interval, and then computes the midpoint from that; to go to the next iteration, either the left or the right point is moved to the mid point ± 1. This implementation instead only keeps track of the left point and the distance to the right point. To me it's not obviously clear that dividing this distance won't skip certain right-side points when the array length is not a power of two. Furthermore, this requires two divisions by two for each iteration, instead of just one.

What is the reason to choose this implementation over a more traditional one?

309–342

I don't see why it would take 9-10 arguments. The inputs seem to be accum_len_arr and seg_len, and the outputs frac and cur_idx. From what I can see, the call to get_curve_points_from_idx(cur_idx, bl, cycl, &p0, &p1, &p2, &p3); can be done outside of that function.

314

I'd prefer cur_step /= 2 instead, as it makes it clearer at first glance that the current value is divided by two. Otherwise you need to carefully read the second cur_step to ensure it's not one of the other cur_xxxx variables.

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

const

This revision now requires changes to proceed.Apr 8 2021, 12:33 PM
Sebastian Parborg (zeddb) marked 25 inline comments as done.

Updated with the latest feedback.

source/blender/blenkernel/intern/anim_path.c
152–154

Added more comments, hope it clears it up.

258–261

We don't have any methods to pick which curve we want to use.
So if you have a curve objects with multiple curve paths stored in it, we use the first one.

Does that answer your question?
I'm not 100% sure what you are asking.

301–305

The base position is not checked by itself.
If we are at cur_step == 0 and gets here, that means that the last position we checked was cur_base and that didn't contain the position we looked for either.

So we don't do this check at the start of after changing cur_step as we haven't checked the last array position yet.

308–312

I took the logic from GCC's bsearch: https://github.com/gcc-mirror/gcc/blob/master/libiberty/bsearch.c

I couldn't use it directly as is because I check two array positions at the same time.

I think it works ok. But we can of course discuss this further if you want it changed.

To me it's unclear how the anim_path_accum_length field relates to the other fields in the CurveCache struct. The name starts with anim_path, so it hints as having something to do with the code in intern/anim_path.c, but that's in no way explicit. It also requires the knowledge of the existance of this file in order to make the connection.

The use of the curve seems to be much broader than just animation-related code, which also makes me doubt whether the chosen naming is clear. After all, why would font rendering code call some BKE_anim_xxxx function? And more importantly, how would someone writing new curve-handling code know that they should be calling BKE_anim_xxx functions?

Updated based on feedback from our latest discussions.

This revision is now accepted and ready to land.Apr 8 2021, 3:47 PM