Dav1dde / gl3n

OpenGL Maths for D (not glm for D).
http://dav1dde.github.com/gl3n/
Other
103 stars 49 forks source link

slerp issues #29

Closed mbj2011 closed 10 years ago

mbj2011 commented 10 years ago

I have absolutely no idea why this is happening, but apprantly there are certain magical quaternions that cannot be interpolated between.

    quat a = quat.yrotation(-1.238796f);
    quat b = quat.yrotation(-1.238796f);    
    quat bad = slerp(a, b, 0.5);    
    quat a2 = quat.yrotation(-1.23879f);
    quat b2 = quat.yrotation(-1.23879f);    
    quat good = slerp(a2, b2, 0.5); 
    writeln(a, " ", b, " ", bad, " ", good, ".");

Having done a bit of research on slerp it turns out that its "bad practice" anyway: http://physicsforgames.blogspot.com/2010/02/quaternions.html http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/

If it is not too much trouble, I'd like to see nlerp along with a fixed version of slerp in the interpolate module. My version looks like this:

quat nlerp(quat a, quat b, float t) {
    float dot = a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;      
    quat result;
    if(dot < 0) {   // Determine the "shortest route"...
        result = a - (b + a) * t;   // use -b instead of b
    } else {
        result = a + (b - a) * t;
    }
    result.normalize();
    return result;
}

, but I guarrantee nothing as the bug above is completely blowing my mind.

Dav1dde commented 10 years ago

This looks another Dlang bug to me...

        writefln("---------> %s | %s", a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z, acos(a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z));
        real theta = acos(a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z);
        writefln("---------> %s", theta);

produces:

---------> 1 | -nan
---------> -nan

Which should obviously be 0 not -nan. No matter what I change, the outcome doesn't change!

Your version looks fine, I added it to the interpolation-module, thanks!

Dav1dde commented 10 years ago

Ok I think I figured it out, the result of the dot product is probably ever so slightly smaller than -1 or bigger than 1, making acos return nan (floating point errors). Clamping the values to -1 and 1 seems to fix it. Please report back, if the issue still exists.