当前位置:   article > 正文

详解四元数

四元数

四元数直观化

逐维了解复数

一维小人理解复数

小人只能理解实数范围内的运算,只是将i当作自身平方为-1的特殊符号

几何意义上,复数范围内的乘,把前一个复数看作是作用在第二个复数上的函数

在这里插入图片描述

固定原点,将(1,0)这个点拉到z点位置,变换之后的w点就是乘积结果,在二维空间中有且仅有一个变换能得到这个结果

这个过程中涉及到拉伸和旋转,拉伸十分好理解,因为一维数轴也能进行。那么旋转呢?这不本就是一个二维平面才有的概念吗?所有旋转都对应着唯一的旋转度数,我们可以将其投影到一维数轴上

想象一个点在单位圆上移动,该点与(-1,0)的连线与复数轴产生交点,一维小人观察复数轴

在这里插入图片描述

在这里插入图片描述

这个点会先到达上方的无限远处,在从下方无限远处出现

二维小人理解三维旋转

新引入一个单位j,表示与复数平面的距离单位,当我们不将其作为Z轴,而是把实数当作是Z轴便于我们更好的理解四元数。

值得一提的是,这样的定义方式并没有很好的乘法准则,例如i*jj*i的结果

同样的,我们定义一个在单位球上的点,以及它和(-1,0)的连线在平面上的交点

在这里插入图片描述

我们对单位球进行旋转操作,与此同时是在平面上的投影会怎么变化呢
在这里插入图片描述

在这里插入图片描述

理解四元数

四元数中包含了三个虚数维度,他们都和实数轴垂直,而且他们之间也相互垂直

在这里插入图片描述

对应的数学性质就是

在这里插入图片描述

同样的,四元数乘法对应的也是相应的变换

在这里插入图片描述

在这里插入图片描述

这个球面代表着所有实部为0的单位四元数

黄色和红色的线代表着两个同心同半径、相互垂直且不相交的圆(在四维中,这很常见)

左下角的公式是通过右手旋转定理得到的

在这里插入图片描述

乘以i的投影变换

在这里插入图片描述

在这里插入图片描述

更为普通的案例,左乘一个四元数-0.5+0.5i+0.5j+0.5k

旋转第一个圆(黄色),让1来到q的位置

然后根据右手法则旋转垂直的圆相同角度(白色)

在这里插入图片描述

三维转动

最容易想到的方法就是一个物体定义三个方向上的圆圈控制方向,但这样就会出现“万向锁”的问题,也就是失去一个自由度

在这里插入图片描述

二维旋转

我们首先现在二维平面中考虑如何进行旋转,假设我们要将(4,1)这个点逆时针旋转30°,如何通过向量运算表示?

在这里插入图片描述

我们延伸到三维旋转中,我们定义一个旋转轴方向上的单位向量

同样的旋转角度的正弦乘以虚部,只不过这次的虚部有三个部分——用于确定旋转单位向量

在这里插入图片描述

这是沿着给定方向旋转40°,**但事实上我们用的是半角!!! ** 为什么?

我们想要知道一个点经过这个变换后的位置,我们要做的并不是要把这两个四元数直接相乘,而是使用一种特殊的“三明治”形式

在这里插入图片描述

一个四元数相乘的可视化网站,也是3Blue1Brown老师亲自制作的(eater.net)——需要翻墙

这里面有一个超级酷炫的功能,就是你能在他的演示视频中直接操作可视化案例通过这个更能理解为何需要右乘一个逆矩阵

为何右乘

首先进行正常的旋转操作,沿着i方向进行旋转

在这里插入图片描述

在这里插入图片描述

然后我们不右乘一个逆矩阵

在这里插入图片描述

可以明显的看到,四维超球在旋转轴上有一个明显的位移——j(i)点,这条黄绿色的线是其在三维空间中的投影

想要消除这个**“副作用”**就要右乘逆矩阵

为何是半角

我们可以从视频网站明显看出,左乘对三维点不仅进行了旋转,还进行了偏移和形变

在这里插入图片描述

i ∗ j = − ( j ∗ i ) i * j = - ( j * i) ij=(ji)
左乘和右乘旋转方向是反的, 有一个负号表示反向
i ∗ j = j ∗ ( − i ) i * j = j * (-i) ij=ji)
也就是左乘i和右乘i的逆矩阵是一样的,两个旋转方向是一致的;但是偏移和形变是相反的,所以只用半角

在这里插入图片描述

Unity中的使用

Unity 3D 中 Rotation

在Unity中,旋转通常可以用一个三维向量(x,y,z)表示。实际上这是欧拉角。三个分量分别是绕x轴、y轴和z轴的旋转角度。

要对一个GameObject进行旋转,可以直接通过如下代码:

transform.Rotate(xAngle, yAngle, zAngle);
  • 1

Editor中Transform组件的旋转轴是父节点的模型空间坐标轴,如果没有父节点,则旋转轴是世界空间坐标轴。

在Script中使用Rotate函数,在Space.Self中旋转

public void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self);
public void Rotate(float xAngle, float yAngle, float zAngle, Space relativeTo = Space.Self);
public void Rotate(Vector3 axis, float angle, Space relativeTo = Space.Self);
  • 1
  • 2
  • 3

在Space.Self中进行旋转,旋转轴就是局部坐标系的坐标轴。

在Space.World中进行旋转,旋转轴是世界坐标系的坐标轴。

由于旋转顺序的不同会导致结果的不同,从文档中可以看到,其transform.Rotate()使用的是Z-X-Y顺规

万向节锁

万向节锁真正会出现问题的是插值动画的时候,物体会沿着一条弧线进行旋转,这是因为由于缺少了一个自由度必须这样进行调节

 transform.eulerAngles = Vector3.Lerp(transform.eulerAngles, new Vector3(150, 90, 90), 0.5f);
  • 1

用四元数进行旋转

​ Unity中的四元数支持和一个Vector3相乘,如果把这个Vector3看作一个向量,那么左乘一个四元数,就相当于对这个向量进行对应的旋转。

transform.rotation = Quaternion.FromToRotation(transform.up, toDirection) * transform.rotation;

  • 1
  • 2

第一个参数是要旋转什么,第二个参数是要旋转到什么方向去这里的三维坐标全是代表一个向量

上面的代码,改成四元数就是

  transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(new Vector3(150,90,90)), dTime);
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/118251
推荐阅读
相关标签
  

闽ICP备14008679号