2

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

这是代码:

    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   
        );
    }

我尝试了许多网站上的实现,但总是有错误的运动。当我尝试简单的线性插值时,动画很流畅,但加速很奇怪。

4

1 回答 1

0

这是一个简单的错误:如果cosTheta< 0.9 并且t= 0,则theta= 0,这意味着Math.sin(theta)= 0,这意味着quatExtend(v2, Math.sin(theta))是零四元数,你最终会返回quatExtend(a, cosTheta),这不是单位四元数。

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

顺便说一句,如果我们在进行代码审查,那cosTheta不是theta. 此外,该if (cosTheta > 0.9)块闻起来像是过早的优化;你可能可以摆脱它。:)

于 2013-08-04T20:12:59.793 回答