如何从前向量、上向量和右向量计算欧拉角?

4
因为这是一个复杂的问题,通常会导致很多混淆(我以前问过类似的问题,但从未正确提出问题并得到答案),所以我将尽可能清楚地表达。

事实:

  • 我正在使用Unity。
  • 我可以轻松地从任何四元数旋转中获得前向、上方和右侧向量。
  • 我不能简单地记录自己的欧拉角,修改它们并通过新的四元数应用旋转,因为对象受物理控制。
  • 我对数学几乎一无所知,除非它是用代码(或伪代码)编写的,因此这对我来说最有益。
  • 对我来说,C++风格的答案最容易理解,但我可以处理几乎任何类型的代码。
  • 我不想让任何人为我编写代码! 我只是要求以代码或伪代码的形式回答,因为我从未学会读普通的数学符号;我是程序员,而不是数学家。
  • Unity使用左手坐标系。 X = 右,Y = 上,Z = 前。

我想做什么:

我试图在人形骨骼结构上播放动画,并使用扭矩(旋转力)将物理布娃娃推到大致相同的姿势。

问题:

我可以完全使用四元数工作,直到需要将扭矩应用于刚体为止。 AddTorque 函数实际上以欧拉角工作,这意味着我不能使用四元数。 我可以轻松地从四元数中提取欧拉角,但它们不可靠并且会导致布娃娃严重抽搐。

我需要什么:

我需要计算可靠的三维欧拉角(即不会随机从+到-翻转)从前向、上方和右侧向量。 我意识到这有点复杂,但这就是为什么我在这里问:我缺乏解决这个问题所需的知识和经验。

鉴于向量本身是可靠的,我认为没有理由不能从它们中计算出可靠的欧拉角。 此外,我不知道我需要或需要哪种旋转顺序的欧拉角,但我相信稍后可以很容易地修改。

任何帮助都将不胜感激!


1
我之前回答过类似的问题;我认为如果你不理解数学,就无法实现解决方案。很抱歉,但物理学就是这样。 - Beta
也许你可以试试我。我能理解相当多的数学,但只有在编码语言中才能理解。 - Clonkex
1
这个 YouTube 视频 说你实际上是在刚体的__本地坐标系__中给出扭矩向量。这与欧拉角无关! - Tobias
2
我从未这样做过。但是对我来说,它看起来是这样的:您可以使用Slerp将两个给定的四元数连接起来。搜索http://courses.cms.caltech.edu/cs171/quatut.pdf以获取“ Slerp”。您可以将其中的参数化为“ t(tSmooth)”,以依赖于您平滑的时间“ tSmooth”获得平滑曲线,对于该曲线,您可以计算角加速度(角速度的公式在论文中给出)。以本地坐标表示的角加速度是您需要进行“ AddTorque”的内容。 - Tobias
对我来说,这看起来非常容易。对于全局坐标中的角速度,您需要计算$q_{10}:=q_1 q_0^{-1}$(Hamilton乘法)。这应该是一个单位四元数(也许您需要进行归一化处理)。从中,您可以读取旋转轴$v$和所需的单位时间旋转速度$\Omega$。您可以使用$v$进行旋转,但需要将其转换为本地框架。首先这样做,并施加一个冲量扭矩到该方向,以查看会发生什么。 - Tobias
显示剩余18条评论
2个回答

8
首先,我想说完全是由于@Tobias的努力,我解决了我的问题。非常感谢!这段时间以来,我一直从错误的角度去解决问题。我认为我需要以特定的方式(使用欧拉角)使用AddTorque并从那里开始工作,但是@Tobias(和稍后的@JarkkoL)指出我需要以不同的方式使用AddTorque。
所以,这就是我在UnityScript(实际上是JavaScript)中所做的:
var quat0:Quaternion;
var quat1:Quaternion;
var quat10:Quaternion;
quat0=transform.rotation;
quat1=target.transform.rotation;
quat10=quat1*Quaternion.Inverse(quat0);
rigidbody.AddTorque(quat10.x,quat10.y,quat10.z,ForceMode.Force);

令人意外的是,这个方法奏效了!它...奏效了!当然,刚体立方体需要很长时间才能平稳下来,但这是因为我需要一个PID控制器。或者,可能需要对quat10进行归一化处理,不确定。我会解决它的 :)

我从没想过你实际上可以单独使用四元数的那一部分。


1
是的,如果你查阅一些有关使用单位四元数表示三维旋转的文献,你会发现 q=[v*sin(angle/2), cos(angle/2)],其中 v 是三维旋转轴(单位向量),angle 是绕轴旋转的角度。 - JarkkoL
2
是的,你可以对四元数应用一整个数学运算类别。例如,如果你需要连接旋转(例如执行分层变换),你只需像矩阵一样将两个四元数相乘即可。 - JarkkoL
q0是在你想要施加扭矩的时间点上,框架的方向。为了将扭矩向量q10转换为相对于q0的坐标,您可以乘以Inverse(q0)q10q0。背景:将q10相对于q0的表示想象为使用Inverse(q0)将q10旋转回来,这只是给出了Inverse(q0)q1Inverse(q0)*q0 = __Inverse(q0)*q1__。(四元数作为旋转齐次坐标) - Tobias
有趣的是,他们在youtube视频中也使用了AddTorque。但是,我没有任何Unity的经验。所以这只是一个猜测。无论如何,感谢您的测试。quat10的标量分量的arcsin应该给出您需要旋转的角度。如果您将其作为角速度步骤并在单位时间后施加相反的角速度步骤(无阻力),则应直接着陆于quat1。祝你好运。 - Tobias
@Tobias 谢谢!我已经设置了一个PID控制器系统,目前正在调整值以使其最佳运行 :) - Clonkex
显示剩余4条评论

1
首先,我认为您在寻求Unity特定问题时会在Unity论坛上有更好的运气(:)。 话虽如此,如果您正在使用AddTorque()接口,则我认为您误解了它的含义。而这个链接http://docs.unity3d.com/ScriptReference/Rigidbody.AddTorque.html可以帮助您。
相比传递欧拉角度数,您需要将旋转轴的向量传递给该函数。我对Unity不太熟悉,但我相信向量的长度指定了要添加多少扭矩。欧拉角度数本质上是旋转的不良表示,因此在涉及旋转时,您应始终假设(除非另有说明)已经建立的API与四元数、轴/角对或矩阵一起工作。欧拉角度数更多地是用户方便的表示方式。

实际上,我不认为在Unity Answers上会更幸运 - 那里的文化甚至不能与SO相提并论,并且似乎很少有专家。关于AddTorque()函数:你是正确的。该函数确实使用向量进行操作。问题在于如何计算出该向量。我即将回答自己的问题,所以您将看到我最终做了什么 :) - Clonkex

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