如何插值旋转?
Posted
技术标签:
【中文标题】如何插值旋转?【英文标题】:How to interpolate rotations? 【发布时间】:2011-02-22 04:39:17 【问题描述】:我有两个描述旋转的向量;一个起始旋转 A 和一个目标旋转 B。我最好如何将 A 插值 F 以接近 B?
当需要对多个维度进行插值(即产生不希望的旋转)时,对向量使用简单的 lerp 无法正常工作。也许从旋转向量构建四元数并使用 slerp 是要走的路。但是,那么,我怎样才能从得到的四元数中提取一个描述新旋转的向量呢?
提前致谢。
【问题讨论】:
你能解释一下为什么 SLERP 不适合你吗?插入多个维度是什么意思,我相信它只是从一个点(向量 A)开始并在另一个点(向量 B)结束,围绕原点进行最短的旋转。 一维以上是指多个轴,例如同时围绕 X 和 Y 旋转,而不是仅围绕单个轴旋转。这就是 LERP 失败的时候。 从根本上说,这没有多大意义,因为无论多轴的每次旋转都等价于 到某个其他轴的旋转。所以真的没有理由为什么线性插值在所有情况下都不起作用。 【参考方案1】:由于我似乎不明白你的问题,这里有一个小SLERP 在 python 中使用 numpy 实现。我使用 matplotlib (v.99 for Axes3D) 绘制了结果。 我不知道你是否可以使用 python,但看起来像你的 SLERP 实现吗?在我看来,结果很好......
from numpy import *
from numpy.linalg import norm
def slerp(p0, p1, t):
omega = arccos(dot(p0/norm(p0), p1/norm(p1)))
so = sin(omega)
return sin((1.0-t)*omega) / so * p0 + sin(t*omega)/so * p1
# test code
if __name__ == '__main__':
pA = array([-2.0, 0.0, 2.0])
pB = array([0.0, 2.0, -2.0])
ps = array([slerp(pA, pB, t) for t in arange(0.0, 1.0, 0.01)])
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
f = figure()
ax = Axes3D(f)
ax.plot3D(ps[:,0], ps[:,1], ps[:,2], '.')
show()
【讨论】:
你有什么理由不把所有的东西都除以so
?数值稳定性...?【参考方案2】:
一个简单的 LERP(和重整化)仅在向量非常接近时才能正常工作,但当向量距离较远时会导致不需要的结果。
有两种选择:
简单的叉积:
使用叉积确定与 A 和 B 都正交的轴 n(注意向量对齐时)并计算 A 和 B 之间的角度 a B 使用点积。现在您可以简单地通过让 a 从 0 到 a 来接近 B(这将是 aNew 并应用 aNew 关于 A 上的轴 n。
四元数:
计算将 A 移动到 B 的四元数 q,并使用 SLERP 用身份四元数 I 对 q 进行插值。然后可以将生成的四元数 qNew 应用于 A.
【讨论】:
【参考方案3】:嗯,您的 slerp 方法会起作用,并且可能在计算上是最有效的(尽管它有点难以理解)。要从四元数返回向量,您需要使用一组可以找到 here 的公式。
还有一些相关的代码here,虽然我不知道它是否对应于你的数据表示方式。
【讨论】:
谢谢。我设法从四元数中取回向量。如果我只在一个轴上插值,则使用 SLERP 的设置可以正常工作。然而,对我来说非常奇怪的是,当使用多个轴时,SLERP 产生的行为与简单向量 LERP 大致相同,也就是说,旋转有时会疯狂地跳跃。有什么想法吗? 听起来你正在获取云台锁;仅当您在正确的坐标中表示旋转时,才能将旋转表示为矢量:en.wikipedia.org/wiki/Gimbal_lock Uhuu,你能澄清一下“围绕多个轴旋转”是什么意思吗?当您在四元数 a 和 b 之间执行 slerp 时,您围绕一个轴旋转;四元数 c 的轴,其中 c = b * a^-1【参考方案4】:如果您决定使用四元数(它会非常好用),请在此处查看我对实施四元数资源的回答: Rotating in OpenGL relative to the viewport
您应该在那篇文章的链接中找到大量示例。
【讨论】:
以上是关于如何插值旋转?的主要内容,如果未能解决你的问题,请参考以下文章