简体   繁体   English

围绕枢轴点旋转RigidBody

[英]Rotating a RigidBody around a pivot point

I'm trying to rotate a rigidbody around a pivot point (in this case the origin), rather than its center of mass. 我试图围绕一个枢轴点(在这种情况下是原点)旋转一个刚体,而不是它的质心。

I had a suggestion to apply three transformations: 我有一个建议应用三个转换:

  1. Transform the rigidbody to the origin 将刚体转换为原点

  2. Rotate the rigidbody on its center of mass 将刚体旋转到质心上

  3. Transform the rigidbody off of the origin. 将刚体转变为原点。

Here is my code: 这是我的代码:

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

However, the pivot points appears to be moving around instead of staying in one place (the origin). 然而,枢轴点似乎在四处移动而不是停留在一个地方(原点)。 Is there a better way (that actually works) to rotate a rigidbody around a pivot point? 是否有更好的方法(实际上有效)围绕枢轴点旋转刚体?

EDIT: I added some sanity-check code for the rotate function: 编辑:我为旋转功能添加了一些健全性检查代码:

//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());

This method actually works, you're just applying it incorrectly. 这个方法确实有效,你只是错误地应用它。 Your second translation is performed along world axis but you have rotated the object, so you have to translate it back along the rotated vector. 您的第二次平移是沿世界轴执行的,但您已旋转了对象,因此必须沿旋转的矢量将其平移。

Correct code should look more or less like this: 正确的代码应该看起来或多或少像这样:

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

I'm not sure if the rotation shouldn't be with minus (I can't check it right now) but you can easily try both. 我不确定旋转是否应该是减去(我现在无法检查)但你可以很容易地尝试两者。

EDIT. 编辑。

Ok, so you forgot to mention that you perform a continuous rotation instead of a single one. 好的,所以你忘了提到你执行连续旋转而不是单个旋转。 This procedure is correct for a single rotation around pivot (eg. 30 degrees rotation). 对于绕枢轴的单次旋转(例如,30度旋转),该过程是正确的。 I've looked into your code once more and I understand that you try to perform your first translation along local x and z-axis. 我再次查看了您的代码,我了解到您尝试沿着本地x和z轴执行第一次转换。 However it is not what happens. 然而,事情并非如此。 In this line: 在这一行:

btVector3 axis = quat.getAxis();

the variable axis is a unit vector representing the axis around which your object is rotated. 变量轴是一个单位向量,表示旋转对象的轴。 It is NOT its coordinate system. 它不是它的坐标系。 I haven't noticed this part before. 我之前没有注意到这部分。 Quaternions are tricky and you should read more about them because many people missuse them. 四元数是棘手的,你应该阅读更多关于它们,因为许多人错过了它们。

A solution that will work in a continuous case is to store the last translation (from center of mass to pivot - in my example it is represented by invTrans) in your object and use it to perform the first translation, then rotate it in the same way it is done, and use it to move to the right position. 在连续情况下工作的解决方案是在对象中存储最后一个转换(从质心到数据透视 - 在我的示例中它由invTrans表示)并使用它来执行第一次转换,然后在同一个转换它完成的方式,并使用它移动到正确的位置。

The corrected code will look like this: 更正后的代码如下所示:

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;

However before starting this whole procedure you have to set offsetToPivot into its position relative to the center of mass. 但是,在开始整个过程​​之前,您必须将offsetToPivot设置为相对于质心的位置。

I have an impression that the main source of your problems is the lack of understanding of linear algebra and basic spatial transformations. 我的印象是,你的问题的主要来源是缺乏对线性代数和基本空间变换的理解。 If you are planning to continue in this field, I strongly recommend reading into this topic. 如果您打算继续这一领域,我强烈建议您阅读本主题。 Also drawing your problem on paper really helps. 在纸上绘制问题确实有帮助。

EDIT2. EDIT2。

Ok, I've tried your code: 好的,我已经尝试过你的代码:

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

After this, temp is equal to {0.000000000, 1.99969542, -0.0349042267} . 此后, temp等于{0.000000000, 1.99969542, -0.0349042267}

In the below function, these transformations perform the three steps you've described: 在下面的函数中,这些转换执行您描述的三个步骤:

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;

namely: 即:

Step 1:Transform the rigidbody to the origin. 第1步:将刚体转换为原点。

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

Step 2:Rotate the rigidbody on its center of mass. 步骤2:在其质心上旋转刚体。

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

Step 3:Transform the rigidbody off of the origin. 第3步:将刚体转变为原点。

    +axisOfRotation.x;
    +axisOfRotation.y;

Here is a recursive function that performs exactly what you need and returns all the consecutively rotated points in a vector: (use it as a benchmark) 这是一个递归函数,它可以完全满足您的需要,并返回向量中所有连续旋转的点:(用它作为基准)

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

where Point is: Point是:

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

For further reading that explains the math behind it here . 进一步的阅读,解释其背后的数学这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM