四元数达到万向节锁定

Yat*_*yte 4 c++ transformation rotation quaternions euler-angles

为了避免在执行旋转时发生角度锁定,我尝试切换到四元数。不知何故,我仍然设法达到云台锁定。

我不确定是否是由于实施的数学方法或设计错误引起的,所以请指出是否应该更改对象坐标的方法。

我的每个对象都有一个X,Y,Z值和一个俯仰,偏航,横滚值。当我更改旋转值时,对象将根据以上信息重新计算其顶点。此逻辑如下:

    // vertex array
    vertices[x] -= /*Offset by origin point*/;

    // Quat.'s representing rotation around xyz axes
    Quaternion q1 = Quaternion(glm::vec3(1,0,0),pitch);
    Quaternion q2 = Quaternion(glm::vec3(0,1,0),yaw); 
    Quaternion q3 = Quaternion(glm::vec3(0,0,1),roll); 

    // total rotation
    Quaternion TotalRot = ( (q3 * q2) * (q1) ); 

    // conversion of original coordinates to quaternion
    Quaternion Point1 = Quaternion(0, vertices[x].x(), vertices[x].y(), vertices[x].z()); 

    // resulting rotated point
    Quaternion Point2 = Quaternion( (TotalRot * Point1) * TotalRot.inverse() );

    // placing new point back into vertices array
    vertices[x] = QVector3D(round(Point2.v.x),round(Point2.v.y),round(Point2.v.z));
    vertices[x]+= /*Undo origin point offset*/;
Run Code Online (Sandbox Code Playgroud)

“ vertices []”是对象顶点数组。上面注释掉的原点偏移量只是为了使对象围绕正确的原点旋转,因此由于围绕该点旋转(相对于?),所以它相对于0,0,0进行了偏移。

我以图形方式表示了我的问题,我先以90度偏航,以45度倾斜,然后以-90度滚动,但滚动轴变得平行于俯仰轴:

问题示例

编辑:

我尝试将这三个轴四元数相乘,然后乘以4x4矩阵,再乘以我的顶点,但是我仍然是万向节锁定/达到奇点!

    Quaternion q1 = (1,0,0,pitch);
    Quaternion q2 = (0,1,0,yaw);
    Quaternion q3 = (0,0,1,roll);
    Quaternion qtot = (q1*q2)*q3;
    Quaternion p1(0, vertices[x].x(), vertices[x].y(), vertices[x].z());
    QMatrix4x4 m;
    m.rotate(qtot);
    QVector4D v = m*p1;
    vertices[x] = QVector3D(v.x(),v.y(),v.z());
Run Code Online (Sandbox Code Playgroud)

Mik*_*son 5

如果您采用欧拉角表示并将其转换为四元数只是为了进行矢量旋转,那么您仍然只是使用欧拉角。只要您在任何地方都涉及欧拉角,万向节锁定问题就会一直存在。如果您想完全消除该问题,您需要完全切换到四元数并且永远不要在任何地方使用欧拉角表示。

这样做的基本方法是,您可以在计算的远端使用欧拉角(作为原始输入或作为最终输出),如果这对您更方便(例如,欧拉角通常更“人性化”)可读”表示)。但是,将四元数用于其他所有内容(并且您可以偶尔转换为旋转矩阵,因为它们对于旋转向量更有效),并且永远不要对任何“坏”旋转表示(欧拉角、轴角等)进行中间转换.) 四元数和旋转矩阵的“无万向节锁定”优势仅适用于在所有计算中坚持使用这两种表示的情况。

因此,一方面,您有单数表示(“万向节锁”的正式术语是单数):

  • 欧拉角(任何种类的,顺便说一下,其中有 12 个);和
  • 轴角。

另一方面,您有无奇点表示:

  • 四元数(更高效的内存和组合操作);和
  • 旋转矩阵(更有效地将旋转应用于向量)。

每当您使用奇异表示操作(例如将多个旋转放在一起,或移动旋转对象)时,您将不得不在每次计算中担心该奇异性。当您使用无奇点表示执行相同的操作时,您不必担心(但您必须担心约束,即四元数的单位范数约束和旋转矩阵的适当正交性)。当然,任何时候当您转换为单数表示或从单数表示转换时,您都必须担心奇点。这就是为什么您应该只在计算的远端(进入或离开时)进行转换,否则在整个计算过程中都坚持使用非奇异表示。

欧拉角的唯一好的目的是为了人类的可读性,句号。


Pet*_* O. 5

您的问题是,即使在使用四元数时,仍要存储三个音高,偏航和侧倾值,而不是四元数来表示对象的方向。

这是在此处使用四元数旋转的方法:

  1. 而不是为每个对象存储X,Y,Z,俯仰,偏航,侧倾,而是orientation 在每个对象中存储X,Y,Z ,其中orientation四元数从初始值(0、0、0、1)开始,这意味着没有旋转。存储每个对象的俯仰,偏航和横滚很容易受到奇异性的影响(万向锁定),因为添加很小的变化后,中间旋转之一(例如,俯仰)可能会导致该对象与旋转轴平行(例如,偏航轴),因此围绕该轴的下一个旋转可能会失败。

  2. 然后,在旋转对象时,确定在该帧期间发生的该对象的俯仰,偏航和滚动(假设您的输入设备以该形式提供旋转),将其转换为四元数,然后将该四元数预乘进入对象的orientation四元数。这种方法不太容易受到奇异性的影响,因为旋转的变化预计在每帧中都非常小。

  3. verticies更改方向后,请勿直接修改对象的X,Y和Z(数组)。相反,当对象的方向发生变化时,请创建一个新的旋转矩阵作为该对象的世界变换矩阵的一部分(以及缩放和平移;为获得最佳结果,请将世界变换计算为translation * rotation * scaling)。

  4. 每隔几帧,应对orientation四元数进行归一化处理,以避免由于舍入误差而导致方向发生不良变化。