从YZX旋转矩阵得到欧拉角存在问题

3

我卡在了从旋转矩阵中获取欧拉角的过程中。

我的约定如下:

  • 左手坐标系(x向右,z向后,y向上)
  • YZX
  • 左手旋转角度

我的旋转矩阵是由欧拉角构建而成的(来自我的代码):

    var xRotationMatrix = $M([
        [1,  0,   0, 0], 
        [0, cx, -sx, 0], 
        [0, sx,  cx, 0], 
        [0,  0,   0, 1]
    ]);

    var yRotationMatrix = $M([
        [ cy, 0, sy, 0], 
        [  0, 1,  0, 0], 
        [-sy, 0, cy, 0], 
        [  0, 0,  0, 1]
    ]);
    var zRotationMatrix = $M([
        [cz, -sz, 0, 0], 
        [sz,  cz, 0, 0], 
        [ 0,   0, 1, 0], 
        [ 0,   0, 0, 1]
    ]);

这将产生一个最终的旋转矩阵,如下所示:
R(YZX) = | cy.cz, -cy.sz.cx + sy.sx,  cy.sz.sx + sy.cx, 0|
         |    sz,             cz.cx,            -cz.sx, 0|
         |-sy.cz,  sy.sz.cx + cy.sx, -sy.sz.sx + cy.cx, 0|
         |     0,                 0,                 0, 1|

我正在使用以下代码从矩阵中计算我的欧拉角:

我正在使用以下代码从矩阵中计算我的欧拉角:

this.anglesFromMatrix = function(m) {
    var y = 0, x = 0, z = 0;

    if (m.e(2, 1) > 0.999) {
        y = Math.atan2(m.e(1, 3), m.e(3, 3));
        z = Math.PI / 2;
        x = 0;
    } else if (m.e(2, 1) < -0.999) {
        y = Math.atan2(m.e(1, 3), m.e(3, 3));
        z = -Math.PI / 2;
        x = 0;
    } else {
        y = Math.atan2(-m.e(3, 1), -m.e(1, 1));
        x = Math.atan2(-m.e(2, 3), m.e(2, 2));
        z = Math.asin(m.e(2, 1));
    }
    return {theta: this.deg(x), phi: this.deg(y), psi: this.deg(z)};
};

我已经反复计算了几遍,但是我看不出问题在哪里。非常感激任何帮助。

请在http://math.stackexchange.com/上提出您的问题。 - Cyril Gandon
3
我本想这样做,但是stackoverflow上关于3D旋转的资料更加丰富。而math.stackexchange声称自己是“为研究数学或从事数学相关专业的人而设”的网站,这并不包括我。 - Brendon McLean
3
@Scorpi0:这是一个适合在这里问的问题。 @Brendon:你的代码看起来不错。我建议尝试一些简单的情况:绕 X 轴旋转 90 度,然后检查结果。然后绕 Y 轴旋转等等。每次只旋转一次,并始终从原始状态开始,不要连续旋转。 - Ali
1
谢谢@Ali - 是的,我试过了。结果是错误的 - 一个旋转影响了两个角度。 - Brendon McLean
2
我真的很失望,这个问题适合在这里讨论。@Brendon,我很高兴你终于找到了那个错别字。 - Ali
3个回答

2
您的矩阵和欧拉角不一致。看起来您应该使用:
y = Math.atan2(-m.e(3, 1), m.e(1, 1));

替代

y = Math.atan2(-m.e(3, 1), -m.e(1, 1));

对于通用情况(else分支)。

我说“看起来像”是因为——这是什么语言?我假设你已经正确地进行了索引。你确定使用atan2吗?在一些编程语言中,正弦项是第一个参数,在其他编程语言中,余弦项是第一个参数,因此没有单一的atan2约定。


我知道最终问题出在一个字符上!你让我的一天都变好了。我已经反复修改了我的计算很多次,但是我的眼睛总是看到它们想看到的东西。 - Brendon McLean

1

anglesFromMatrix函数的最后一个也是最重要的分支存在一个小的符号错误,但除此之外它可以正常工作。使用:

y = Math.atan2(-m.e(3, 1), m.e(1, 1))

由于只有m.e(3, 1)的值需要被反转,而m.e(1, 1) = cy.czm.e(3, 1) = -sy.cz的值不需要反转。我还没有检查其他分支是否存在错误。

请注意,由于sz = m.e(2, 1)有两个解,用于构建矩阵m的角度(x, y, z)可能与anglesFromMatrix(m)返回的角度(rx, ry, rz)不同。因此,我们可以测试从(rx, ry, rz)构建的矩阵rm是否确实等于m


感谢@antonakos。我刚刚注意到了两个解决方案的问题(以及极点周围的问题),目前它会导致一些非常酷的绕这些点旋转的双角度。但是我认为我可以通过使用矩阵驱动我的旋转并仅使用欧拉角记录静止状态来解决这个问题。感谢您的答案。 - Brendon McLean
@Brendon:极点附近的行为被称为“万向节锁定”。在3D图形中避免这个问题的常见方法是使用四元数。 - Landei

0

我花了很多时间研究如何为给定的矩阵找到正确的角度。数学上的问题在于无法确定 SIN 的精确值,因为 -SIN(x) = SIN(-x),这会影响矩阵的其他值。我想出的解决方案可以从八个可能的解中得出两个同样有效的解。我使用了标准的 Z . Y . X 矩阵形式,但它适用于任何矩阵。首先从以下三个角度中找到三个角度:X = atan(m32,m33):Y = -asin(m31):Z = atan(m21,m11):然后创建角度 X' = -sign(X)*PI+X:Y'= sign(Y)*PI-Y:Z = -sign(Z)*pi+Z。使用这些角度创建八组角度组:XYZ:X'YZ:XYZ':X'YZ':X'Y'Z':XY'Z':X'Y'Z:XY'Z。使用这些组创建八个相应的矩阵。然后对未知矩阵和每个矩阵之间的差异进行求和。这是未知元素与测试矩阵的相同元素之间的差的总和。做完这个之后,两个总和将为零,并且这些矩阵将表示原始矩阵的解角度。这适用于所有可能的角度组合,包括 0。随着 0 的引入,越来越多的八个测试矩阵变得有效。在 0,0,0 时,它们都变成了单位矩阵!希望这有所帮助,对我的应用程序非常有效。Bruce 更新 在上面的解决方案中发现 Y = -90 或 90 度存在问题后,我想出了这个解决方案,它似乎可以在所有值下重现矩阵! X = if(or(m31=1,m31=-1),0,atan(m33+1e-24,m32)) Y = -asin(m31) Z = if(or(m31=1,m31=-1),-atan2(m22,m12),atan2(m11+1e-24,m21)) 我走了很长的路才找到这个解决方案,但它非常有启发性 :o)希望这有所帮助!Bruce


注意:我试图重新创建用于创建3D矩阵的角度。使用这种解决方案,其中一个集合始终是用于创建矩阵的原始角度。两个解决方案集都是完全相同的矩阵,无法从解决方案方面区分它们。 - Bruce McElwee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接