-
-
Notifications
You must be signed in to change notification settings - Fork 20.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cubic interpolation of rotations in 3d transform animation track is unpredictable. #40592
Comments
I've been using https://github.com/KhronosGroup/glTF-Sample-Models/tree/5bbe0b378d703a506ce8ae12c7dc829e42546d3b/2.0/InterpolationTest to test too, but it's also different. |
Ok, I checked the source code and the code for cubic slerps for quats looks really sketchy to me: Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!q.is_normalized(), Quat(), "The end quaternion must be normalized.");
#endif
//the only way to do slerp :|
real_t t2 = (1.0 - t) * t * 2;
Quat sp = this->slerp(q, t);
Quat sq = prep.slerpni(postq, t);
return sp.slerpni(sq, t2);
} If I get it right ( |
@fire I'm not familiar with the whole glTF stuff, but it seems weird to me that with cubic interpolation the cube on gif stops overy 90 degrees. |
This may be related to the wobbly/"wrong way around" interpolation of Quat when using cubic_slerp I stumbled upon as seen in this video: Code for this test can be found from: What I expected was cubic_slerp to smoothen out those slight discontinuities in direction seen in slowed-down camera movement when piecewise (slerp) linear interpolation switches between "pieces", something like the SQUAD here: "Disclaimer": I'm not very familiar with quaternions (just used them first time here, because I needed some kind of interpolation of orientations), so there might be false assumptions etc. in the text above. (Edit: Apparently github was smart/intrusive enough to already dig the reference from my recent commit...) Godot version: 3.2.2.stable |
I implemented https://math.stackexchange.com/questions/2650188/super-confused-by-squad-algorithm-for-quaternion-interpolation 's SQUAD but still testing cubic interpolation algorithm, had some bugs. Will report back with a branch and maybe a pr. |
I've seen that math exchange post as I was searching for quat interpolation algorithms and I thought that the issue described there looked suspiciously similar to what I've been experiencing with Godot. I'm still confused by the whole concept of helper quaternions and unsure where they exactly fit into the whole thing as well how they are actually calculated. The behaviour on the gif looks like what I would expect SQUAD to behave like. Also, as a side note I find it weird and misguiding to call SQUAD |
I submitted a pull request. #41626 Edited: If I remove the initial wobbly, the math breaks the interpolation demos from GLTF2. |
Tried the fix with my "flying car demo": https://youtu.be/ZhJpJgQBAsU |
Video: https://youtu.be/ZhJpJgQBAsU May be related to: godotengine/godot#40592
Can you make a flying demo for me to test with? Not sure if it's open source. |
It can be found here: https://github.com/GNSS-Stylist/LOSolverDemo_Godot/tree/godot_quat_interpolation_issue |
I don't see a test case that uses cubic_slerp? |
You can change interpolation method of the car by changing "LOSolver_TimeShift"'s "Quat Interpolation Method". Quats used in the interpolation are printed in lower left corner. See my post above for some more info. |
Added a clamp function, and testing the change on cubic_slerp. Edited: Interested in http://www.cemyuksel.com/research/interpolating_splines/ but one step after the other. Get this quat patch complete first. |
Video: https://youtu.be/61QawNpJeOA May be related to: godotengine/godot#40592 This version skips 3/4 of the lines (="keyframes") of the source (*.LOScript) files. You can change this using "readLineSkip" in LOScriptReplayer.gd.
There seem to be discontinuities when using the latest commit ( 5c6e45e ) in some cases, see https://youtu.be/61QawNpJeOA Some instructions can be found from readme.md, few most relevant in this context /changed (changed also some namings (hopefully better) and other stuff from the previous version):
Sorry for this late reply, I didn't have time/energy to build anything usable before. |
If you're interested there's a survey of orientation interpolation methods at http://www.adrian-haarbach.de/interpolation-methods. The most interesting are listed below:
They also have an executable demo with runtime costs. |
Update bug project for latest master. |
Investigated this further (in godot 4) as I'm planning to use this for camera track with sparsely placed keys. Have to admit that I'm still "super confused" (as someone else in the stackexchange-link above)... But after days of mostly trials and errors managed to get somewhat smooth-looking movements out. 2022-01-24.22-02-23.mp4Red cube and axes show slerped rotations for comparison, blue cube shows the next key, green cube cubic_slerped rotations. There are 4 identical keys between 20...26 s. Cubic_slerped object actually first rotates a bit over the "rest-position" there before settling and takes identical "step back" before going on. Not sure if this is how squad should work(?) However calculation of those helper quaternions uses quaternion log-function that has a division with the length of the vector part of the quaternion (that becomes zero when some of the subsequent source quaternions are identical) so I wrote some code to handle these cases. Anyone know how helper "tangent" quaternions are supposed to be calculated when some rotations are identical? Here's another video from a running project: 2022-01-24.18-05-02.mp4Bottom part has the same objects as the previous video, on top there's objects following the same rotations as my previous videos/godot projects (red = slerped, green = cubic_slerped, yellow lines connecting the points used for interpolation). Godot project (Godot 4): Quaternion.c&h (Godot 4) sources: Not sure if this is the way this is supposed to work. There are also some limits and such in the source files that are just thrown there and "seemed to work" so this is definitely not "release ready" code. But feel free to utilize these if you find them helpful. Edit: |
I'll investigate your notes over this week and the next. |
Discussed with @TokageItLab . We discussed modified akima may be able to solve this. Tokage posted some plots of modified akima. The main part is the graphs and not the text. When I last talked to @reduz about this issue, he mentioned it was ok to replace the current cubic with |
Above images are quoted from: (c) sikino(2020)(c) 1994-2022 The MathWorks |
You mean using (modified) akima directly for quaternion's component (i, j, k, w-values) and normalize afterwards? Have to admit that I had doubts if this kind of interpolation would work nicely (still being confused). To see the differences I made a modification to the code that returns component-wise interpolated (lerp) and normalized quaternion from cubic_slerp-function. This is how it looks like with almost the same data as before (there are some keys added to the end of the animation, though): 2022-01-26.12-08-46.mp4As the differences are so small I moved the slerped and (now)lerped version on top of each other and re-colored the traces of lerp to yellow. AnimationPlayer-version on the left. Difference doesn't actually look too bad. Lerp moves faster at the start and end of the interpolated range (as expected), but at least with these rotations the effect isn't so big. However it can be seen on the colored cubes quite easily. On the more densely keyed version on the right it's actually hard to even distinguish them. Would be nice if users could choose between interpolation modes. I have no idea how/if this could be done, though. Stumbled upon quite thorough discussion about very similar issues on blender forum: Modified Godot-project: Modified quaternion-sources (cubic_slerp = lerp): |
The implementation that directly interpolate each element and does the normalization is probably wrong. I guess we need to adopt the difference and norm of the two quaternions into the modified akima formula. |
While twiddling with this I decided to test also component-wise interpolation with standard cubic-interpolation. Here's the result: 2022-01-28.22-07-26.mp4To the eye looks to be quite close to squad. Code (not pretty, just a quick hack to test this):
Personally I will probably stick to this for now (as it is good enough for my use case) but will still keep my eyes open for other methods. Modified akima looks quite nice indeed. Edit: Added flipping of quaternions when needed (previous version interpolated long way around now and then). |
Headsup, I moved your project into a github git repo, I want to try the modified akima interpolation. Reference |
@GNSS-Stylist I wish to use this an a benchmark for Godot Engine for 1) testing slerping vs cubic slerping 2) cubic slerping 1000 transforms for networking replication. What are your thoughts? To do that a license compatible or exactly the same as the Godot Engine MIT license is required. |
In my opinion, this issue seems to be confusing two issues.
I'm not sure about issue 1, as I haven't tested it properly, but if it's true about issue 1, I think we should close this issue and repost the these issues since these problems have different fundamental causes. |
Made a pull request with added LICENSE-file (MIT) for @fire 's repo: fire-archive/godot-40592#1. Added Jon Ring (@jonri) and Roujel Williams (@SIsilicon) to the "copyright-list" also, since the first person controller was created and modified by them. Personally I don't really care much about the copyright here, but can't decide on behalf of others. Have to agree with @TokageItLab that this issue got somewhat bloated over time. |
Why am I here? |
@SIsilicon The first person controller used in the repo above was originally written by you ( https://github.com/SIsilicon/Godot-Ocean-Demo ) so the "copyright-list" entry also made it way here. |
The first person controller isn't mine actually. If you look in the credits section of my project you'll see I got it from a tutorial by Jeremy Bullock, almost line for line. So if anything, you should credit him. |
Reopened because we posted a new attempt at fixing this. |
Godot version:
v.3.2.2.stable.official, v.3.2.3.beta.custom_build.bdd1e7486 (bdd1e74)
OS/device including version:
Gentoo/Linux x86_64
Issue description:
Cubic interpolation of 3d rotations seems to produce unpredictable splines.
I tried to create a 3D animation using 3D transform track in AnimationPlayer node. I made 3 keyframes in total.
In the first two keyframes, the rotation of the node is unchanged, in the third, the object is rotated. Interpolating the animation with nearest and linear options seems to work fine. However if I switch the track interpolation to cubic, the node rotates towards the angle specified in the third keyframe and the back to the original angle within the period between first two keyframes. Then, after the second keyframe it bounces off and rotates again towards the angle specified in the third keyframe as it should.
Expected result: the node's rotation should stay unchanged during the period between first two keyframes (wrapping is set to clamp), then after the second frame it should smoothly rotate towards the angle specified by the third keyframe.
Steps to reproduce:
The simplest scenario has been already described above, however other animations of rotation of 3d transform also result unexpected interpolations. Some of these interpolations seem to be not even continuous (eg.: the rotation "bouncing" off the angle defined by keyframe instead of going through it smoothly).
The simplest steps for reproduction would be:
Minimal reproduction project:
godot_animation_bug.zip
The text was updated successfully, but these errors were encountered: