Summary: | Quaternion SLERP not working jumping and returning incorrect interpolation | ||
---|---|---|---|
Product: | [JogAmp] Jogl | Reporter: | Tek <fwdk98003> |
Component: | graph | Assignee: | Rami Santina <rami.santina> |
Status: | RESOLVED FIXED | ||
Severity: | critical | CC: | gouessej, harvey.harrison, org.jogamp, rami.santina, sgothel |
Priority: | P4 | ||
Version: | 2 | ||
Hardware: | All | ||
OS: | all | ||
Type: | --- | SCM Refs: |
2b3bb9426385d97375c3312f5c0f4e2a827b1fbb
|
Workaround: | --- |
Description
Tek
2013-03-13 23:18:26 CET
Thank you Tek, I hope Rami can solve it. This code looks correct to me. It's derived from: m = ((sin(θ) * (1 - t)) / sin(θ)) * qa n = ((sin(θ) * t) / sin(θ)) * qb q(t) = m + n Where: θ = arcos(qa · qb) According to "Mathematics for 3D Game Programming". Unfortunately, I don't have unit tests for it. (In reply to comment #2) > This code looks correct to me. > > It's derived from: > > m = ((sin(θ) * (1 - t)) / sin(θ)) * qa > n = ((sin(θ) * t) / sin(θ)) * qb > Hmm, something seems off in the above...doesn't that simplify down to simple LERP ((sin(θ) * (1 - t)) / sin(θ)) .. (sin(θ) / sin(θ)) * (1 - t) .. (1 - t) Looking at the link, I think what you wanted was: m = ((sin(θ * (1 - t))) / sin(θ)) * qa n = ((sin(θ * t)) / sin(θ)) * qb Also, the above falls down when sin(θ) == 0 (quarternions aligned or extactly 180 degress apart) Have a look at the following: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ Which covers the aligned and nearly-opposite cases correctly. Harvey Not compiled, not tested, just the code I have lying around from lunch. public void slerp(Quaternion a, Quaternion b, float t) { float cosom = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; float t1 = 1.0f - t; // if the two quaternions are close, just use linear interpolation if (cosom >= 0.95f) { x = a.x * t1 + b.x * t; y = a.y * t1 + b.y * t; z = a.z * t1 + b.z * t; w = a.w * t1 + b.w * t; return; } // the quaternions are nearly opposite, we can pick any axis normal to a,b // to do the rotation if (cosom <= -0.99f) { x = 0.5f * (a.x + b.x); y = 0.5f * (a.y + b.y); z = 0.5f * (a.z + b.z); w = 0.5f * (a.w + b.w); return; } // cosom is now withion range of acos, do a SLERP float sinom = FloatUtil.sqrt(1.0f - cosom * cosom); float omega = FloatUtil.acos(cosom); float scla = (float)FloatUtil.sin(t1 * omega) / sinom; float sclb = (float)FloatUtil.sin( t * omega) / sinom; x = a.x * scla + b.x * sclb; y = a.y * scla + b.y * sclb; z = a.z * scla + b.z * sclb; w = a.w * scla + b.w * sclb; } (In reply to comment #4) > Not compiled, not tested, just the code I have lying around from lunch. > ... http://jogamp.org/git/?p=jogl.git;a=commit;h=2b3bb9426385d97375c3312f5c0f4e2a827b1fbb Thank you! @Tek: Please test. And if you can, please add a unit tests or two! (Via email .. or better git pull req.) Let me test the code. I'll get back to you in few hours |