四元数混合是错误的

时间:2013-07-26 08:40:48

标签: math opengl animation

我正在通过SLERP进行Quaternion混音,但我的实现做了一些非常错误的事情。您可以在此视频中看到它:video

以下是代码:

    cosTheta = quatDot(a, b);       
    if (cosTheta > 0.9){
        var quat = new Vec4(
            a.x + (b.x - a.x)*t,
            a.y + (b.y - a.y)*t,
            a.z + (b.z - a.z)*t,
            a.w + (b.w - a.w)*t             
            );
        normalizeQuat(quat);
        return quat;
    }
    cosTheta = Math.min(Math.max(cosTheta, -1), 1); //clamp

    var theta = Math.acos(cosTheta) * t;

    var v2 = quatMinus(b, quatExtend(a, cosTheta));
    normalizeQuat(v2);      
    return quatSum(quatExtend(a, cosTheta), quatExtend(v2, Math.sin(theta)));

我有自己的帮助功能:

function quatDot(a,b){
    return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
    }
    function quatMultiply(q,p){
        return new Vec4(
            q.w * p.x + q.x * p.w + q.y * p.z - q.z * p.y,
            q.w * p.y + q.y * p.w + q.z * p.x - q.x * p.z,
            q.w * p.z + q.z * p.w + q.x * p.y - q.y * p.x,
            q.w * p.w - q.x * p.x - q.y * p.y - q.z * p.z);
    }
    function quatExtend(q, t){
    return new Vec4(
        q.x * t, q.y * t, q.z * t, q.w * t);
    }
    function quatMinus(q, p){
        return new Vec4(
            q.x - p.x,
            q.y - p.y,
            q.z - p.z,
            q.w - p.w   
        );
    }
    function quatSum(q, p){
        return new Vec4(
            q.x + p.x,
            q.y + p.y,
            q.z + p.z,
            q.w + p.w   
        );
    }

我尝试过很多来自网站的实现,但总是有错误的移动。当我尝试简单的线性插值时,动画是平滑的,但奇怪的是加速。

1 个答案:

答案 0 :(得分:0)

这是一个简单的错误:if cosTheta< 0.9和t = 0,然后theta = 0,这意味着Math.sin(theta) = 0,这意味着quatExtend(v2, Math.sin(theta))是零四元数,你最终返回{{1} },这不是一个单位四元数。

我希望正确的实现能够将其中一个四元数的逆(或共轭)至少一次,并且永远不要调用normalizeQuat。但那只是直觉。为了超越直觉,尝试编写单元测试!

顺便说一下,如果我们正在进行代码审核,那么quatExtend(a, cosTheta)不是cosTheta的余弦会让人感到困惑。此外,theta块闻起来像过早优化;你可以摆脱它。 :)