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

slerp breaks flag for quaternion normalization #51

Closed
hyrodium opened this issue Nov 2, 2021 · 11 comments · Fixed by #78
Closed

slerp breaks flag for quaternion normalization #51

hyrodium opened this issue Nov 2, 2021 · 11 comments · Fixed by #78

Comments

@hyrodium
Copy link
Collaborator

hyrodium commented Nov 2, 2021

julia> q1 = Quaternion(1.0, 0.0, 0.0, 0.0, true)
Quaternion{Float64}(1.0, 0.0, 0.0, 0.0, true)

julia> q2 = Quaternion(0.0, 1.0, 0.0, 0.0, true)
Quaternion{Float64}(0.0, 1.0, 0.0, 0.0, true)

julia> slerp(q1,q2,0.3)
Quaternion{Float64}(0.8910065241883678, 0.45399049973954675, 0.0, 0.0, false)

The flag false should be true here because slerp keeps norm of quaternion if the input quaternions are unit quaternions.

@sethaxen
Copy link
Collaborator

I agree, this would be sensible. The only thing to check is if after repeated application of slerp, the norm of the output drifts away from 1.

@hyrodium
Copy link
Collaborator Author

hyrodium commented Feb 19, 2022

Thanks for the comment! I will make a PR to resolve this issue after #60 is discussed.

@sethaxen
Copy link
Collaborator

Since #60 proposes a breaking change and this issue doesn't, proceeding with a PR anyways would be useful.

@hyrodium hyrodium changed the title slerp breaks flag for quaternion normaliation slerp breaks flag for quaternion normalization Feb 21, 2022
@hyrodium
Copy link
Collaborator Author

hyrodium commented Feb 21, 2022

Oh, I just noticed we also have linpol funciton.

julia> q1 = Quaternion(1.,0.,0.,0.,true)
QuaternionF64(1.0, 0.0, 0.0, 0.0, true)

julia> q2 = Quaternion(0.,1.,0.,0.,true)
QuaternionF64(0.0, 1.0, 0.0, 0.0, true)

julia> linpol(q1, q2, 0.2)
QuaternionF64(0.9510565162951535, 0.3090169943749474, 0.0, 0.0, true)

julia> slerp(q1, q2, 0.2)
QuaternionF64(0.9510565162951535, 0.3090169943749474, 0.0, 0.0, false)

I think slerp is more common word, so it seems better to deprecate linpol function.

@sethaxen
Copy link
Collaborator

Are they entirely equivalent, or is there some combination of inputs for which they will produce different results?

@hyrodium
Copy link
Collaborator Author

Note that these functions return different values for non-unit quaternion.

julia> q3 = Quaternion(2.,1.,0.,0.,true)
QuaternionF64(2.0, 1.0, 0.0, 0.0, true)

julia> q4 = Quaternion(3.,0.,0.,0.,true)
QuaternionF64(3.0, 0.0, 0.0, 0.0, true)

julia> slerp(q3, q4, 0.2)
QuaternionF64(2.0, 1.0, 0.0, 0.0, true)

julia> linpol(q3, q4, 0.2)
QuaternionF64(2.2, 0.8, 0.0, 0.0, true)

My question is, what's the expected behavior of slerp with non-unit quaternion?
I think we have the following choices:

  • Normalize all input quaternions, and the return value is always unit quaternion. (like linpol)
  • Throws DomainError for non-unit quaternion.
  • Return exp(log(q1)*(1-t) + log(q2)*t) for any quaternions.

@hyrodium
Copy link
Collaborator Author

The following are references on slerp, all of which deal with unit quaternions.

Slerp is shorthand for spherical linear interpolation

https://en.wikipedia.org/wiki/Slerp

spherical interpolating between the rotated value ...

http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

Spherically interpolates between quaternions a and b by ratio t.

https://docs.unity3d.com/ScriptReference/Quaternion.Slerp.html

@sethaxen
Copy link
Collaborator

For additional background, linpol was present in the original check-in of the package (351d657), and slerp was added in #6, with no discussion about linpol.

@hyrodium
Copy link
Collaborator Author

@keesvp @SimonDanisch
Do you have any thoughts on this?

@hyrodium
Copy link
Collaborator Author

I tried searching for linpol in GitHub public repositories, but I couldn't find it.
https://github.com/search?q=language%3Ajulia+linpol&type=code

@hyrodium
Copy link
Collaborator Author

On the current master branch, slerp is faster than linpol.

julia> q1 = Quaternion(1.,0,0,0,true)
QuaternionF64(1.0, 0.0, 0.0, 0.0, true)

julia> q2 = Quaternion(0,1.,0,0,true)
QuaternionF64(0.0, 1.0, 0.0, 0.0, true)

julia> slerp(q1,q2,0.2)
QuaternionF64(0.9510565162951535, 0.3090169943749474, 0.0, 0.0, false)

julia> linpol(q1,q2,0.2)
QuaternionF64(0.9510565162951535, 0.3090169943749474, 0.0, 0.0, true)

julia> @benchmark slerp($q1,$q2,0.2)
BenchmarkTools.Trial: 10000 samples with 994 evaluations.
 Range (min  max):  30.258 ns  47.363 ns  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     30.450 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   30.738 ns ±  1.569 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

   █                                                           
  ▇█▄▂▂▂▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▁▂▂▁▂▂▂▂▂▂▂ ▂
  30.3 ns         Histogram: frequency by time        37.4 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark linpol($q1,$q2,0.2)
BenchmarkTools.Trial: 10000 samples with 991 evaluations.
 Range (min  max):  40.956 ns  120.753 ns  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     41.835 ns               ┊ GC (median):    0.00%
 Time  (mean ± σ):   42.864 ns ±   5.312 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

  ▄█▇▂                                                      ▁▂ ▁
  ████▆▆▇██▇▅▇▆▅▁▃▄▅▁▃▃▄▃▁▁▅▄▄▅▃▁▄▄▃▄▃▄▄▃▃▄▁▁▁▃▄▁▁▁▁▁▁▃▁▁▃▁███ █
  41 ns         Histogram: log(frequency) by time      67.6 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants