【问题标题】:Quaternion rotation without Euler angles没有欧拉角的四元数旋转
【发布时间】:2013-06-07 07:31:57
【问题描述】:

this comment 中强烈建议我们永远不要使用欧拉角。我知道欧拉角存在一些限制,尤其是万向节锁定,但我想知道在没有欧拉角的情况下通常使用的最佳技术或技术集?

关于这个主题的大多数讨论都涉及从欧拉角转换为四元数,这是一件简单的事情。但是我读过的关于在没有欧拉角的情况下进行旋转的唯一方法是使用以下技术从两个向量中创建一个四元数,如 Stan Melax 在“游戏编程宝石”中的文章“最短弧四元数”中所述:

template <typename T>
inline QuaternionT<T> QuaternionT<T>::CreateFromVectors(const Vector3<T>& v0, const Vector3<T>& v1)
{

    Vector3<T> c = v0.Cross(v1);
    T d = v0.Dot(v1);
    T s = std::sqrt((1 + d) * 2);

    QuaternionT<T> q;
    q.x = c.x / s;
    q.y = c.y / s;
    q.z = c.z / s;
    q.w = s / 2.0f;
    return q;
}

这是链接评论中提到的方法吗?

【问题讨论】:

  • 这可能有助于读者知道评论说“即使您使用四元数,您仍在使用它们 [欧拉角]”。这有助于解释问题的动机。
  • "关于这个主题的大多数讨论都涉及从欧拉角转换为四元数" 不,他们没有。我从未见过任何关于从欧拉角转换为四元数的讨论。我见过关于使用一个而不是另一个的讨论,但我从未见过有人说“用它们制作 3 个四元数,将它们相乘,你的问题就会结束!”
  • 我认为人们对这个问题的概念的理解之间确实存在一些根本性的脱节。真的很难理解和谈论这个问题,因为人们要么对他们试图解释的内容有一个非常根本的误解。另一方面,专家们不再真正理解在所有抽象级别上掌握这件事有多难。因此,虽然人们可以在某种程度上谈论如何处理不同系统的机制。然后其他人在没有真正说明这一点的情况下谈论数据的插值。

标签: math graphics 3d transformation


【解决方案1】:

方向

方向是变换在坐标系中对对象进行定向的方式。方向是一个绝对量,如位置或标量。方向在概念上是一个值。还有一些操作可以应用于方向,具体取决于它们的表示。

与向量和标量不同,方向可以用多种方式表示。

“使用欧拉角”是什么意思?

欧拉角是围绕 3 个固定的正交轴进行 3 次旋转的系列。这些应用的顺序很重要,通常是按照惯例确定的。

“使用欧拉角”意味着欧拉角是您的代码存储和操纵对象方向的方式。你最终如何组合这些角度来生成一个矩阵并不重要。重要的是您的代码会将方向视为 3 个角度。例如,当您对方向应用旋转偏移时,它将作为旋转角度的偏移提供,这些偏移将直接应用于存储的欧拉角。

“使用矩阵”是什么意思?

我知道没有人这么说,但我要在这里说明一点。

“使用矩阵”意味着旋转矩阵是您的代码存储和操作对象方向的方式。如果某段代码想要旋转对象,它们将在左侧或右侧应用一个矩阵。即使该矩阵是通过一些轴向旋转来计算的,代码仍然对 矩阵 执行基本操作,而不是角度。

“使用四元数”是什么意思?

出于本讨论的目的,“四元数”是用于对方向进行编码的 4 元素单位向量。四元数可以对它们进行类似矩阵的操作,例如合成和反转。四元数必须保持归一化才能正确编码方向。

“使用四元数”意味着您将对象的方向和操作存储为四元数。你所有关于方向的操作,在最基本的层面上,都是在处理四元数数学。

如何调整方向

欧拉角经常被使用,因为它们(理论上)可以直观地调整:您只需增加或减少一个角度。如果您想将对象在 X 轴上旋转 -10 度,您只需从 X 轴旋转中减去 10。但是我们不想使用它们,因为它们很糟糕,所以让我们看看其他方向表示。

要将方向调整为矩阵,您必须做两件事。您必须将当前方向与偏移旋转矩阵相乘(如果您想在 X 轴上旋转 -10 度,则为此创建一个角度/轴矩阵并将其右乘)。然后,由于计算机的精度有限,您必须重新正交化矩阵。如果您不执行第二步,您的矩阵最终将不再是正交矩阵,从而不再是 orientation

对矩阵进行正交归一化很难。这就是我们使用四元数的(部分)原因。标准化一个四元数很容易;它只是 4 元素向量归一化。而且由于四元数和矩阵具有类似的运算,相同的数学将适用于两者。所以它们看起来几乎一模一样。

【讨论】:

  • 欧拉不一定基于固定轴。你如何表示结果并不重要,因此矩阵你不能很好地用它们插值旋转。
  • @joojaa:相对于先前的旋转固定。 X 欧拉角将始终围绕 X 轴旋转,相对于先前的旋转。
  • 是的,但是您可以相对于先前的旋转,或者您实际上可以将其固定为原始旋转。两者都是可能的。我不知道这一点,因为您从未见过另一个使用过,但有时会在非常旧的代码中看到它。前者更容易聚合成矩阵乘法。
  • 此外,虽然正交归一化绝对是游戏代码的问题,但这不是我使用 quats 的原因,因为无论如何我总是从组件组成矩阵。没有一个模型会出现正交归一问题。所以这里有两种方法来处理这个问题。
【解决方案2】:

有几种数学模型可以描述 3D 对象的旋转。欧拉角模型只是其中之一。通常当人们谈到欧拉角时,他们实际上是在谈论 Tait-Bryan 角,欧拉只提出了第一个角度重复的模式,例如 ZXZ 旋转。如果您按照预期使用下摆,则欧拉角没有什么特别的错误,即用于静态表示。或者,它们适用于实际上像万向节一样的许多机械旋转。

欧拉角有两个主要缺点。首先是人们通常认为他们更了解欧拉角数值表示。虽然实际上它只是真正正确的,只要只有 2 个和非常少的特殊 3 轴旋转旋转正在进行,即使在某些有限情况下它也有点可疑。第二个是你不能真正有意义地对欧拉模型进行插值,因为它没有均匀地填充旋转空间。这意味着数字空间的某些区域具有不同的大小。想象一下矩形地图在球体上是如何变形的。

今天,我们中的很多人都在为图形制作动画,在模拟工程中,插值至关重要。这意味着欧拉模型并不真正适合大多数任务。人们在尝试考虑欧拉模型空间中的插值时会想到的一件奇怪的事情是,您实际上可以一次围绕 3 个方向旋转。但这在物理上是不可能的,因为 3d 空间中只有一次旋转。

现在您可以使用的其他模型很少。可以使用仿射矩阵作为奖励,您可以定义所有坐标系。但在所有其他模型中,这是最糟糕的解决方案,它甚至没有用数字有意义地插入一个轴。再一次是存储结果的好模型。可以使用基于矢量和旋转的轴角度。这是物理上非常合理的表示旋转的方式,但在解决最短路径时存在某些问题。现在插值的最佳模型可能是四元数,它是一种奇怪的轴角编码。它有几个有趣的属性,例如所有可能旋转的空间正好是 2 倍,因此可用于解决 2 个姿势之间的最短旋转和最长旋转。 quats 的缺点是大多数人无法以任何有意义的方式读取数值的结果。

所以你有它。欧拉模型描述旋转没有错。只要您不需要进行数值插值,除了非常小的子集。这恰好是空中使用的飞机。或者如果你不需要一个统一的空间,不需要随机生成旋转等等。

没有什么说您不能在一个模型中设置值并在另一个模型中进行插值。

【讨论】:

  • 如果你要描述一个完全没有欧拉的旋转,你会如何构造四元数?
  • @Fellowshee:你将如何构造一个欧拉角?从数字上讲,四元数就是encoding of an angle/axis rotation。任何其他构造方法都建立在此之上。
  • @NicolBolas 好的,非常感谢所有这些答案。对于该领域的新手来说,这是一个很容易被误解的重要话题。
【解决方案3】:

顺便说一句,理想情况下,我希望看到像原始评论员 @NicolBolas 这样的权威专家的回答。但是由于他到目前为止还没有回复您的comment question,所以我会尝试一下。

我想知道这里的混淆是否在于“欧拉”角与其他角的含义。

您提到“有关此主题的大多数讨论都涉及从欧拉角转换为四元数”。但他们真的是从欧拉角度转换的吗?

该评论的作者是apparentlythis tutorial 的作者。在本教程的示例 8.1 中,他从轴和角度展示了四元数的公式。这是您所说的“从欧拉角转换为四元数”的事情吗?显然他并不是说你不应该从一个角度创建一个四元数。

来自wikipedia definition of Euler angles,他们三人一组。换句话说,角度 Euler 的角度是它们被组合以表示方向的方式。我怀疑comment 所指的是这样一个事实,即您以欧拉角 pitchAccum 和 yawAccum 累积旋转,然后将这些角度中的每一个转换为四元数,然后再使用四元数乘法组合它们。

如果您在开头创建了一个四元数来表示方向;然后在四元数本身中累积方向状态,而不是在欧拉角 pitchAccum 和 yawAccum 中,然后你会做@NicolBolas (Jason) 所提倡的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多