簡體   English   中英

使用四元數補間旋轉

[英]Tweening a rotation with quaternions

在Actionscript 3中,我有一個3D對象,它圍繞着它的x,y和z軸隨機旋轉。 我希望能夠將其停在適當位置,然后將其旋轉到指定的旋轉,並采用盡可能短的路徑。 似乎四元數是工作的正確工具,但我不確定如何正確地補間它。 我正在嘗試補間軸角度旋轉,然后將其轉換為四元數。 到目前為止,這是我的測試代碼。

var startV3DV:Vector.<Vector3D> = new <Vector3D>[positionV3D, new Vector3D(0,1,0,0), scaleV3D];
var endV3DV:Vector.<Vector3D> = new <Vector3D>[positionV3D, new Vector3D(0,1,0,Math.PI), scaleV3D];
var recomposeV3DV:Vector.<Vector3D> = new <Vector3D>[positionV3D, new Vector3D(0,0,0,0), scaleV3D];

TweenMax.to(startV3DV[1], 2, {x:endV3DV[1].x, y:endV3D[1].y, z:endV3D[1].z, w:endV3D[1].w, onUpdate:quat});

var quatV3D:Vector3D = new Vector3D();
function quat():void {
    quatV3D.x = currentV3D[1].x * Math.sin(currentV3D[1].w * .5);
    quatV3D.y = currentV3D[1].y * Math.sin(currentV3D[1].w * .5);
    quatV3D.z = currentV3D[1].z * Math.sin(currentV3D[1].w * .5);
    quatV3D.w = Math.cos(currentV3D[1].w * .5);
    recomposeV3DV[1] = quatV3D;
    myMatrix3D.recompose(recomposeV3DV,"quaternion");
}

它實際上會使對象繞y軸旋轉很長一段時間,但是當它碰到PI / 2時,它會出錯並且在重構線上得到“ArgumentError:Error#2004:其中一個參數無效”,我認為其中一個quatV3D屬性不適合四元數公式。 有關如何正確做到這一點的任何想法?

我無法使用您提供的數據重現它。 但是在使用currentV3D Vector時,你似乎正在使用startV3DV,這在你的示例代碼中沒有提到。 它可能包含無效數據,如0軸或0刻度。

此外,這不是四元數應該如何用於補間。 你似乎試圖在這里做的是兩個軸/角度表示之間的補間,然后每次更新時生成一個四元數。 您也可以使用內置的“axisAngle”旋轉模式直接重建。 這可能不會做你期望的事情,因為1)它不能保證采取最短的角度,2)當軸不同時 - 所有的投注都是關於插值的樣子;)

你應該做的是將開始和結束旋轉轉換為四元數,就像你當前在quat()中做的那樣,並在它們之間進行插值。 你仍然需要糾正最短的路徑:如果兩個四元數之間的4分量點積<0,你將需要否定其中一個的所有分量。 最后,你將不得不重新規范quat(同樣是4分量,旋轉四元數必須是單位長度)。

如果你想堅持TweenMax,你仍然可以做這樣的事情(可能包含一些粗心的錯誤,但你應該得到要點):

    t = 0;
    TweenMax.to(this, 2, {t:1, onUpdate:lerp});

    function lerp() : void
    {
        var x:Number, y:Number, z:Number, w:Number;
        var w1:Number = start.w, x1:Number = start.x, y1:Number = start.y, z1:Number = start.z;
        var w2:Number = end.w, end:Number = end.x, y2:Number = end.y, z2:Number = end.z;
        var len:Number;

        // shortest direction
        if (x1*x2 + y1*y2 + z1*z2 + w1*w2 < 0) {
            x2 = -x2;
            y2 = -y2;
            z2 = -z2;
            w2 = -w2;
        }

        x = x1 + t*(x2 - x1);
        y = y1 + t*(y2 - y1);
        z = z1 + t*(z2 - z1);
        w = w1 + t*(w2 - w1);

        len = 1.0/Math.sqrt(x*x + y*y + z*z + w*w);

        quatV3D.x = x*len;
        quatV3D.y = y*len;
        quatV3D.z = z*len;
        quatV3D.w = w*len;

        recomposeV3DV[1] = quatV3D;
        myMatrix3D.recompose(recomposeV3DV,"quaternion");
    }

您可能還需要研究球面線性插值(“slerp”),它們與線性插值不同,具有恆定的角速度。 我會很懶,只是指導你去幾年前寫的Away3D Quaternion課程: https//github.com/away3d/away3d-core-fp11/blob/008b1d83d3330281034b90ca7072722a9f486958/src/away3d/core/math/Quaternion 。如

希望這可以幫助!

事實證明,Matrix3D已經可以使用四元數做LERP了:

var startM3D:Matrix3D = myObject.transform.matrix3D.clone();
var endM3D:Matrix3D = new Matrix3D(new <Number>[-1.2000000476837158,0,1.0490733615142744e-7,0,0,1.2000000476837158,0,0,-1.0490733615142744e-7,0,-1.2000000476837158,0,220,150,0,1]);
var currentM3D:Matrix3D = new Matrix3D();

var t:Number = 0;
TweenMax.to(this, 4, {t:1, onUpdate:lerp});

function lerp():void {
    currentM3D = Matrix3D.interpolate(startM3D, endM3D, t);
    myObject.transform.matrix3D = currentM3D;
}

補間看起來很不錯。 不過,我會試試你的SLERP。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM