四元数旋转的物理意义以及代码实现-偏应用向

四元数旋转的物理意义以及代码实现

前言:

虽然有点不务正业,但是这个被这个问题卡住的我,真的是寝食难安,毕竟我刚开始以为这个只是一个两小时的问题。
话不多说,先整文档吧,就当一个学习笔记。

四元数的理解

参考资料:

  1. https://www.bilibili.com/video/av33385105?from=search&seid=12110128311072054550
  2. https://www.bilibili.com/video/av35803047?from=search&seid=12110128311072054550
  3. 《3D数学基础:图形与游戏开发》
  4. https://blog.csdn.net/qq_28773183/article/details/80083607 这篇博客的概念和图都比较不错
  5. https://blog.csdn.net/yukinoai/article/details/88591682 代码参照这位博主的,但是他的表述方式让我有点迷糊,左右不容易分清。
  6. 我的坐标系动态旋转演示视频:https://www.bilibili.com/video/av57256823/

先是四元数的理解和计算.

一般来说大家都会提到哈密顿大佬的故事和复数的概念,大家看看上面的教程就好了。以及四元数的优势和缺点,简单说说,
首先最大的就是,四元数不好理解,所以我想写这个笔记,也许会给大家一些帮助。
其次四元数无法表示转180°和超过180°的旋转。尤其是180°,sin(180°/2)=0,这时候的p1,p2,p3都不存在。
但是四元数的优点也比较明显(虽然我没看出来,要不是别人用的是这个,我没办法改,我早放弃了!):简洁、不混淆,好像会避免万向锁的问题,以及用四个数就可以表示一个旋转,而不像旋转矩阵需要九个数。

这里假定大家都能理解这些基本知识。
不能理解应该也无所谓,毕竟我们作为一个嗑盐搬砖狗,利用这些数学知识,解决实际问题就好。
所以,捋清我们的问题:

明确问题:

现在想用四元数来表示坐标系或者向量的旋转,我们已知一个在坐标系O下的向量P(x0,y0,z0),然后所在坐标系发生了旋转,旋转量为Quat[q0, q1, q2, q3],变成了新的坐标系A,那么向量P在新的坐标系A中的三维坐标应该是多少?和Quat的关系如何?如果再转一次呢?

向量旋转-其实就是坐标系的旋转

四元数的定义如下:

quat = [q0, q1, q2, q3]

待旋转的向量为:

P = [p0, p1, p2]

其中quat中q0代表实数,物理含义为旋转角度一半的余弦,即cos(theta/2)=q0,其中theta为旋转角度。
q1,q2,q3为ijk三个基的值,也就是一个旋转轴向量,分别可以对应XYZ轴的分量值,具体对应关系如下:

q1=x*sin(theta/2)
q2=y*sin(theta/2)
q3=z*sin(theta/2)

然后旋转的效果是,原始的坐标轴(不是向量!),绕着(x,y,z)这个旋转向量的指向方向,逆时针,也就是右手坐标系(注意,这里默认都是右手法则)旋转theta角度,得到新的坐标系, 然后原始向量P在新的坐标系下的坐标自然就会变化成为P’=[p0’, p1’, p2’].
具体对应关系如下。

P_new = Quat*P*Quat_inverse

以一个简单的例子,四元数的实际计算公式和代码实现:

在这里插入图片描述

动态图可以看上面的b站视频。
然后具体的值和公式如下:
对于原始坐标系下的一个向量P(0, 2, 0),这时候会有一个quat的旋转,其实这个quat表示的是它的坐标系旋转了!
然后这个quat一般会是单位四元数,为啥是单位四元数呢?因为我们的计算公式是:p_new = quatpquat_inverse。
而quat_inverse = quat*/|quat|,
(quat就当成共轭了)也就是quat的共轭除以它的模,共轭特别好求,但是模需要计算,所以直接将模变成1,quat_inverse=quat
好了,我们现在知道了单位quat,那么也就知道了quat_inverse
下面进行计算,直接调用四元数乘法公式,这个上面的参考资料都有,我就不放出来了,直接上代码:

P = [0, 2, 0]
# 将只有三个值的纯四元数转成可以计算的真实四元数
P = [0, P[0], P[1], P[2]]
# 已知单位四元数的数值!
quat = [0.7071, 0.7071, 0, 0]
quat_inverse = [quat[0], -quat[1], -quat[1], -quat[2]]

# 四元数乘法函数!每次只算两个相乘就好了,只需要分开左右就行了!
Def mul(left, right):
# 尽量用一个copy()进行深复制,万一原始数据变了就乱了
        left = left.copy()
        right = right.copy()
        s = left[0]*right[0] - left[1]*right[1] - left[2]*right[2] - left[3] * right[3]
        x = left[0]*right[1] + left[1]*right[0] + left[3]*right[2] - left[2] * right[3]
        y = left[0]*right[2] + left[2]*right[0] + left[1]*right[3] - left[3] * right[1]
        z = left[0]*right[3] + left[3]*right[0] + left[2]*right[1] - left[1] * right[2]
        return [s, x, y, z]

quat_P = mul(quat, P)
P_new = mul(quat_P, quat_inverse)
print("P_new:", P_new)
# P_new(0, 0, 0, -2)

上面是公式计算出来的坐标系旋转后,新向量值。下面用图来表示,空间中到底是咋转的:

用四元数表示坐标系旋转的物理意义:

如果是坐标系的话,那么就将坐标系每个轴当成被旋转的向量,都旋转了之后,就会称为新的坐标系.
举个例子:右手法则的世界坐标系(X, Y, Z)如下图:

然后表示旋转的单位四元数是这样:quat = [0.7071, 0.7071, 0 , 0]
那么它的旋转角是:

theta = np.arccos(0.7071)*2*np.pi/180
# theta = 90°

XYZ轴的分量是:

R_x = 0.7071/np.sin(theta/2)
# R_x = 1.0

其它两个轴的计算都是0,所以旋转向量是:(1.0, 0, 0),下图的黑色向量。
旋转角和旋转轴都拿到了,局势就很明朗了,转就完事儿了。
在这里插入图片描述

下面该怎么转?
沿着旋转轴的正方向,逆时针转theta角度,就OK了。
首先原Y轴要绕(1.0, 0, 0)正方向逆时针旋转90°,变成新的X轴.但是朝向变成了原坐标系Z轴的正方向.
Z轴也是,变成新的Z轴,朝向为原Y轴负方向.
X轴就不会变化,因为涉及到旋转的垂直分量和平行分量,只有和旋转轴垂直的分量才会有转动效果;
而X轴和旋转轴水平,自然不会有旋转效果.
这里就会形成一个新的坐标系
在新的坐标系中,向量P的坐标变成了(0, 0, -2)!!!
是不是和上面公式计算出来的一样?!!
OK了,基本上四元数表示旋转的概念和实现都完成了,其它复杂的计算,直接用公式就好了,
具体理解的话,可以用参考资料12中的可视化图,看看旋转轴到底在哪儿,但是无法看出转之后的变化。
差不多就OK了~

  • 19
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hehedadaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值