四元数到达万向节锁 [英] Quaternion reaching gimbal lock

查看:105
本文介绍了四元数到达万向节锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了在执行旋转时避免角度锁定,我尝试切换到四元数.不知何故,我仍然设法达到万向节锁定.

In attempt to avoid angle lock when performing rotations I've tried to switch over to Quaternions. Somehow, I'm still managing to reach gimbal lock.

我不确定是因为我实施的数学运算还是设计错误,所以请指出我是否应该更改对象坐标的方法.

I'm not sure if its due to the math I've implemented, or a design error, so please point out if I should change my approach for my object coordinates.

我的每个对象都有一个 X、Y、Z 值和一个俯仰、偏航、滚动值.当我更改旋转值时,对象会根据上述信息重新计算其顶点.这个逻辑如下:

Each of my objects hold an X,Y,Z value, and a pitch,yaw,roll value. When I change a rotation value, the object recalculates its vertices based on the above information. This logic is as follows:

    // 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*/;

"vertices[]" 是对象顶点数组.上面注释掉的原点偏移只是为了让对象围绕正确的原点旋转,因此它相对于 0,0,0 移动,因为旋转发生在该点周围(对吗?).

"vertices[]" is the objects vertex array. The origin point offset commented out above is just so that the object is rotated around the proper origin point, so it is shifted relative to 0,0,0 since rotations occur around that point (right?).

我有我的问题的图示,我首先偏航 90,俯仰 45,然后滚转 -90,但滚轴与俯仰轴平行:

I have a pictorial representation of my problem, where I first yaw by 90, pitch by 45, then roll by -90, but the roll axis became parallel to the pitch axis:

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

I tried multiplying those 3 axis quaternions together, then multiplied by a 4x4 matrix, followed by multiplying that by my vertex point, but I still gimbal lock/reach singularity!

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

推荐答案

您的问题是,即使您使用四元数,您仍然存储三个俯仰、偏航和滚转值,而不是四元数,以表示物体的方向.

Your issue is that even when you're using quaternions, you're still storing three pitch, yaw, and roll values, rather than a quaternion, to represent an object's orientation.

以下是使用四元数进行旋转的方法:

Here's how you should use quaternions for rotation here:

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

  1. Instead of storing X, Y, Z, pitch, yaw, roll for each object, instead store X, Y, Z, orientation in each object, where orientation is a quaternion starting at the initial value (0, 0, 0, 1), meaning no rotation. Storing pitch, yaw, and roll for each object is vulnerable to singularities (gimbal lock) because as small changes are added, one of the intermediate rotations (say, a pitch) could result in the object being parallel to a rotation axis (say, the yaw axis), so that the next rotation about that axis could fail.

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

Then, as an object is rotated, determine the pitch, yaw, and roll for that object that occurred during that frame (assuming that your input device provides the rotation in that form), convert it to a quaternion, then pre-multiply that quaternion into the object's orientation quaternion. This approach is less vulnerable to singularities because the changes in the rotation are expected to be very small each frame.

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

Don't modify the object's X, Y, and Z (your verticies array) directly after changing the orientation. Instead, when an object's orientation changes, create a new rotation matrix to serve as part of the object's world transformation matrix (along with scaling and translation; for best results, calculate the world transform as translation * rotation * scaling).

每隔几帧,您应该对 orientation 四元数进行归一化,以避免由于舍入误差而导致方向发生不希望的变化.

Every few frames, you should normalize the orientation quaternion to avoid undesirable changes in the orientation, which can happen due to rounding error.

这篇关于四元数到达万向节锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆