Skip to content
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

Quat::slerp dot threshold prevents extrapolation when difference in angle is smaller than about π / 49.65 #356

Open
zopsicle opened this issue Oct 25, 2022 · 2 comments
Labels
help wanted Extra attention is needed

Comments

@zopsicle
Copy link

zopsicle commented Oct 25, 2022

I’m using Quat::slerp to extrapolate rotations, and it works perfectly when the angle is greater than about π / 49.65, in which case the dot product is 0.9994995, suspiciously close to the dot threshold of 0.9995 where Quat::slerp falls back to Quat::lerp. However, when the angle is smaller than that, e.g. π / 60.00, then extrapolation no longer works properly, and the rotation goes slower as the s parameter to Quat::slerp goes further beyond 1.0.

Example code:

let start = Quat::from_axis_angle(Vec3::X, 0.0);
let end   = Quat::from_axis_angle(Vec3::X, PI / 49.65);
println!("{:?} {:?}",
    Quat::dot(start, end),
    Quat::slerp(start, end, 49.65 * 2.0).to_axis_angle());
// => 0.99949956 (Vec3(-0.023733087, -0.0, -0.0), 6.2778816)

let start = Quat::from_axis_angle(Vec3::X, 0.0);
let end   = Quat::from_axis_angle(Vec3::X, PI / 60.00);
println!("{:?} {:?}",
    Quat::dot(start, end),
    Quat::slerp(start, end, 60.00 * 2.0).to_axis_angle());
// => 0.99965733 (Vec3(1.0000001, 0.0, 0.0), 2.5490494)

Notice how in the first example, the resulting angle is 2π, i.e. properly extrapolated; whereas in the second example, the resulting angle is not even close to 2π.

I’m not quite sure why the special case for small angles exists; is it merely an optimization? Or is it there to avoid problems with precision? I saw in #57 that the implementation of Quat::slerp was based on that in cgmath. But cgmath falls back to nlerp, not lerp, which might behave differently.

It would be nice to have extrapolation work as expected, like it does for e.g. Vec3::lerp. Do you think that would be acceptable, perhaps as a separate method?

(Or maybe I shouldn’t use quaternions for animations. EDIT: I have since switched to using axis–angle representation for animations and it works better, also because it can handle rotations larger than 180° properly.)

@zopsicle zopsicle changed the title Quat::slerp dot threshold prevents extrapolation when difference in angle is greater than about π / 49.65 Quat::slerp dot threshold prevents extrapolation when difference in angle is smaller than about π / 49.65 Oct 25, 2022
@bitshifter bitshifter added the help wanted Extra attention is needed label Dec 5, 2022
@aloucks
Copy link
Contributor

aloucks commented Jan 31, 2023

as the s parameter to Quat::slerp goes further beyond 1.0.

It's been a long time since I've thought about any of this, but I don't think it will work if the s value exceeds 1.0. Does it work in cgmath? (and does it work with the older version of cgmath circa #57?)

glam's version of lerp normalizes (or at least it did?) and it is/was/i-thought equivalent to cgmath's nlerp.

Regarding your question about the dot threshold, the implementation is derived from the following:
http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/

@aloucks
Copy link
Contributor

aloucks commented Nov 28, 2023

Maybe related: #275

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants