[英]Rotating a RigidBody around a pivot point
我試圖圍繞一個樞軸點(在這種情況下是原點)旋轉一個剛體,而不是它的質心。
我有一個建議應用三個轉換:
將剛體轉換為原點
將剛體旋轉到質心上
將剛體轉變為原點。
這是我的代碼:
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.