2015-09-09 129 views
3

我試圖圍繞樞軸點(在本例中是原點)旋轉剛體,而不是其質心。圍繞樞軸點旋轉剛體

我有一個建議,應用三個轉變:

  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()); 
+1

您應該將支點轉換爲原點,然後旋轉,然後應用反轉換。 – paddy

+0

我已經編輯了我的答案。 – Estiny

+0

對於我來說,假設offsetToPivot最初設置爲'btVector3(0.0,2.0,0.0)',那麼這兩個代碼片段的工作原理完全相同。如果它被設置爲'btVector3(-2.0,0.0,0.0);'它顯然不會工作,因爲你試圖圍繞它所在的軸旋轉點,這當然會將它放在同一個地方。 – Estiny

回答

1

這種方法的實際工作,你只是將它正確。您的第二個翻譯是沿着世界座標軸執行的,但是您已經旋轉了該對象,因此您必須沿旋轉的矢量將其翻譯回來。

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

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}

+0

謝謝你的回覆,但我不完全確定你的意思。不應該是與應用於rigidBody的相同旋轉(現在有一個btVector3)?我嘗試使用這個代碼,但它導致剛體在上下移動時在它的質心上旋轉。這個剛體是否必須具有0的高度才能起作用? – Jaitnium

+0

感謝您的更新。我明白你現在在做什麼,但我仍然認爲代碼是不正確的。我打印出invTrans並且它看起來與bt-> offsetToPivot相同;所以由於某種原因,invRot沒有得到正確應用。 – Jaitnium

+0

@Jaitnium你知道......我不能在任何地方運行這個代碼,所以它是從我的腦海裏寫出來的,我無法檢查它。如果你明白這個方法,你至少可以試着自己解決。你在哪一行打印這些值?你看到行'btPhys-> offsetToPivot = invTrans;'?在這條線後,他們應該是平等的。你的RigidBody的行爲是什麼?你將什麼初始值分配給'offsetToPivot'?開始旋轉時,最初的「WorldTransform」是什麼?您是否按照我的建議嘗試過使用調試器? – Estiny

1

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

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

如需進一步閱讀,請說明背後的數學問題here

+0

那麼使用Bullet的意義在哪裏?Btw。你的變換隻能在2D平面上旋轉一個'Point' ,而問題是圍繞3D軸旋轉一個'Rigid Body',它比這更復雜一點,即使你把它縮放到3D空間(這很痛苦),你仍然只計算身體,但方向在哪裏? – Estiny

+0

@Esti你是對的。我會更新答案以符合問題要求,道歉! – Ziezi