簡體   English   中英

圍繞樞軸點旋轉RigidBody

[英]Rotating a RigidBody around a pivot point

我試圖圍繞一個樞軸點(在這種情況下是原點)旋轉一個剛體,而不是它的質心。

我有一個建議應用三個轉換:

  1. 將剛體轉換為原點

  2. 將剛體旋轉到質心上

  3. 將剛體轉變為原點。

這是我的代碼:

btMatrix3x3 orn = btPhys->getWorldTransform().getBasis();   
btQuaternion quat;
orn.getRotation(quat);
btVector3 axis = quat.getAxis();

//Move rigidbody 2 units along its axis to the origin
btPhys->translate(btVector3(-2.0 * axis.getX(), 0.0, -2.0 * axis.getZ()));

//Rotate the rigidbody by 1 degree on its center of mass
orn *= btMatrix3x3(btQuaternion( btVector3(1, 0, 0), btScalar(degreesToRads(-1))));
btPhys->getWorldTransform().setBasis(orn);  

//Update axis variable to apply transform on
orn.getRotation(quat);
axis = quat.getAxis();

//Move the rigidbody 2 units along new axis
btPhys->translate(btVector3(2.0 * axis.getX(), 0.0, 2.0 * axis.getZ())); 

然而,樞軸點似乎在四處移動而不是停留在一個地方(原點)。 是否有更好的方法(實際上有效)圍繞樞軸點旋轉剛體?

編輯:我為旋轉功能添加了一些健全性檢查代碼:

//Code that doesn't work
btVector3 invTrans = btPhys->offsetToPivot.rotate(btVector3(1.0, 0.0, 0.0), btScalar(degreesToRads(-1)));
//Values printed out are identical to offsetToPivot
printf("invTrans: %f %f %f\n", invTrans.getX(), invTrans.getY(), invTrans.getZ());

//Sanity code that DOES work
//Arbitrary vector
btVector3 temp = btVector3(0.0, 2.0, 0.0);
temp = temp.rotate(btVector3(1.0, 0.0, 0.0), btScalar(degreesToRads(-1)));
printf("temp %f %f %f\n", temp.getX(), temp.getY(), temp.getZ());

這個方法確實有效,你只是錯誤地應用它。 您的第二次平移是沿世界軸執行的,但您已旋轉了對象,因此必須沿旋轉的矢量將其平移。

正確的代碼應該看起來或多或少像這樣:

btMatrix3x3 orn = btPhys->getWorldTransform().getBasis();   
btQuaternion quat;
orn.getRotation(quat);
btVector3 axis = quat.getAxis();

//Move rigidbody 2 units along its axis to the origin
btPhys->translate(btVector3(-2.0 * axis.getX(), 0.0, -2.0 * axis.getZ()));

//Rotate the rigidbody by 1 degree on its center of mass
orn *= btMatrix3x3(btQuaternion( btVector3(1, 0, 0), btScalar(degreesToRads(-1))));
btPhys->getWorldTransform().setBasis(orn);  

//Get rotation matrix
btTransform invRot(btQuaternion(btVector3(1, 0, 0), btScalar(degreesToRads(-1))),btVector3(0,0,0));
//Rotate your first translation vector with the matrix
btVector3 invTrans(-2.0 * axis.getX(), 0.0, -2.0 * axis.getZ());
invTrans = invRot * invTrans;

//Update axis variable to apply transform on
orn.getRotation(quat);
axis = quat.getAxis();

//Translate back by rotated vector
btPhys->translate(-invTrans); 

我不確定旋轉是否應該是減去(我現在無法檢查)但你可以很容易地嘗試兩者。

編輯。

好的,所以你忘了提到你執行連續旋轉而不是單個旋轉。 對於繞樞軸的單次旋轉(例如,30度旋轉),該過程是正確的。 我再次查看了您的代碼,我了解到您嘗試沿着本地x和z軸執行第一次轉換。 然而,事情並非如此。 在這一行:

btVector3 axis = quat.getAxis();

變量軸是一個單位向量,表示旋轉對象的軸。 它不是它的坐標系。 我之前沒有注意到這部分。 四元數是棘手的,你應該閱讀更多關於它們,因為許多人錯過了它們。

在連續情況下工作的解決方案是在對象中存儲最后一個轉換(從質心到數據透視 - 在我的示例中它由invTrans表示)並使用它來執行第一次轉換,然后在同一個轉換它完成的方式,並使用它移動到正確的位置。

更正后的代碼如下所示:

btMatrix3x3 orn = btPhys->getWorldTransform().getBasis();   
btQuaternion quat;
orn.getRotation(quat);

//Move rigidbody 2 units along its axis to the origin
btPhys->translate(btPhys->offsetToPivot);

//Rotate the rigidbody by 1 degree on its center of mass
orn *= btMatrix3x3(btQuaternion( btVector3(1, 0, 0), btScalar(degreesToRads(-1))));
btPhys->getWorldTransform().setBasis(orn);  

//Get rotation matrix
btTransform invRot(btQuaternion(btVector3(1, 0, 0), btScalar(degreesToRads(-1))),btVector3(0,0,0));
//Rotate your first translation vector with the matrix
btVector3 invTrans = invRot * btPhys->offsetToPivot;

//Update axis variable to apply transform on
orn.getRotation(quat);
axis = quat.getAxis();

//Translate back by rotated vector
btPhys->translate(-invTrans); 
btPhys->offsetToPivot = invTrans;

但是,在開始整個過程​​之前,您必須將offsetToPivot設置為相對於質心的位置。

我的印象是,你的問題的主要來源是缺乏對線性代數和基本空間變換的理解。 如果您打算繼續這一領域,我強烈建議您閱讀本主題。 在紙上繪制問題確實有幫助。

EDIT2。

好的,我已經嘗試過你的代碼:

btVector3 temp = vec3(0,2,0);
btTransform invRot(btQuaternion(btVector3(1, 0, 0), btScalar(-0.017453f)),btVector3(0,0,0));
temp = invRot * temp;

此后, temp等於{0.000000000, 1.99969542, -0.0349042267}

在下面的函數中,這些轉換執行您描述的三個步驟:

int x = cos(angRads) * (initial.x - axisOfRotation.x) - sin(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.x;      
int y = sin(angRads) * (initial.x - axisOfRotation.x) + cos(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.y;

即:

第1步:將剛體轉換為原點。

    initial.x - axisOfRotation.x
    initial.y - axisOfRotation.y

步驟2:在其質心上旋轉剛體。

    cos(angRads) * initial.x - sin(angRads) * initial.y
    sin(angRads) * initial.x + cos(angRads) * initial.y 

第3步:將剛體轉變為原點。

    +axisOfRotation.x;
    +axisOfRotation.y;

這是一個遞歸函數,它可以完全滿足您的需要,並返回向量中所有連續旋轉的點:(用它作為基准)

rotateCoordinate(vector<Point>& rotated, Point& axisOfRotation, Point initial, 
                            float angRads, int numberOfRotations){
    // base case: when all rotations performed return vector holding the rotated points
    if(numberOfRotations <= 0) return;
    else{
        // apply transformation on the initial point
        int x = cos(angRads) * (initial.x - axisOfRotation.x) - sin(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.x;
        int y = sin(angRads) * (initial.x - axisOfRotation.x) + cos(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.y;
        // save the result
        rotated.push_back(Point(x, y));
        // call the same function this time on the rotated point and decremented number of rotations
        rotateCoordinate(rotated, axisOfRotation, Point(x,y), angRads, numberOfRotations -1);
    }
}

Point是:

struct Point {
    int x, y;
    Point(int xx, int yy) : x(xx), y(yy) { }
    Point() :x(0), y(0) { }
};

進一步的閱讀,解釋其背后的數學這里

暫無
暫無

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

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