四元数:Quaternion,四维数域内的数,可用于描述点在三维空间内的旋转(因为三维的旋转可以理解为绕某个轴旋转一个角度,所以需要4个维度的信息)
注意这里的旋转的轴,指的是从原点到
(
x
,
y
,
z
)
(x,y,z)
(x,y,z),也就是单纯的旋转信息,不包含位移信息(绕着不通过原点的线,可以先把点和轴平移,再旋转,再把点平移回去)
来源:
二元数:
a
+
b
i
a+bi
a+bi表示二维坐标系内的向量
v
⃗
=
(
a
,
b
)
\vec v =(a,b)
v=(a,b),当这个向量为单位向量的时候,也可以表示为旋转这个操作,旋转的角度:
θ
=
<
(
1
,
0
)
,
v
⃗
>
\theta = <(1,0),\vec v>
θ=<(1,0),v>。例如:
v
⃗
=
(
1
,
0
)
n
=
3
2
+
1
2
i
,表示逆时针旋转
3
0
∘
v
⃗
∗
n
=
3
2
+
1
2
i
(
3
0
∘
)
v
⃗
∗
n
∗
n
=
1
2
+
3
2
i
(
6
0
∘
)
v
⃗
∗
n
∗
n
∗
n
=
0
+
1
i
(
9
0
∘
)
v
⃗
∗
n
∗
n
∗
n
∗
n
=
−
1
2
+
3
2
i
(
12
0
∘
)
.
.
.
\vec v = (1,0) \\ n = \frac{\sqrt 3}{2}+\frac{1}{2}i,表示逆时针旋转30^\circ\\ \vec v *n=\frac{\sqrt 3}{2}+\frac{1}{2}i (30^\circ)\\ \vec v *n*n=\frac{1}{2}+\frac{\sqrt 3}{2}i(60^\circ)\\ \vec v *n*n*n=0+1i(90^\circ)\\ \vec v *n*n*n*n=-\frac{1}{2}+\frac{\sqrt 3}{2}i(120^\circ)\\ ...
v=(1,0)n=23+21i,表示逆时针旋转30∘v∗n=23+21i(30∘)v∗n∗n=21+23i(60∘)v∗n∗n∗n=0+1i(90∘)v∗n∗n∗n∗n=−21+23i(120∘)...
那三维坐标系内呢?假设定义三元数:
a
+
b
i
+
c
j
a+bi+cj
a+bi+cj,表示三维向量
v
⃗
=
(
a
,
b
,
c
)
\vec v =(a,b,c)
v=(a,b,c),同时表示一个三维空间的旋转,那么自乘的结果内,有一项为
2
b
c
∗
i
j
2bc*ij
2bc∗ij。而数学家无法给这个
i
j
ij
ij设定一个值完成逻辑自洽(例如
i
∗
i
=
−
1
i*i=-1
i∗i=−1)。
为了完成逻辑自洽,引入了
k
=
i
j
k=ij
k=ij,也就是变成了四元数:
q
=
a
+
b
i
+
c
j
+
d
k
q=a+bi+cj+dk
q=a+bi+cj+dk,同时加上以下设定:(不满足交换律)
i
×
j
=
k
j
×
k
=
i
k
×
i
=
j
j
×
i
=
−
k
k
×
j
=
−
i
i
×
k
=
−
j
i
×
j
×
k
=
k
×
k
=
−
1
i\times j=k\\ j\times k=i\\ k\times i=j\\ j\times i=-k\\ k\times j=-i\\ i\times k=-j\\ i\times j\times k=k\times k=-1
i×j=kj×k=ik×i=jj×i=−kk×j=−ii×k=−ji×j×k=k×k=−1
这样子,我们就可以让乘法的结果也是
a
+
b
i
+
c
j
+
d
k
a+bi+cj+dk
a+bi+cj+dk了
几何意义:
定义四元数 q = a + b i + c j + d k q=a+bi+cj+dk q=a+bi+cj+dk,参考二元数的共轭值定义, q ∗ = a − b i − c j − d k q^*=a-bi-cj-dk q∗=a−bi−cj−dk
轴为
n
⃗
=
(
x
,
y
,
z
)
\vec n=(x,y,z)
n=(x,y,z),角为
θ
\theta
θ时,可以推出各个系数为(系数推理参考):
a
=
c
o
s
θ
2
(
F
Q
u
a
t
:
:
W
)
b
=
s
i
n
θ
2
x
(
F
Q
u
a
t
:
:
X
)
c
=
s
i
n
θ
2
y
(
F
Q
u
a
t
:
:
Y
)
d
=
s
i
n
θ
2
z
(
F
Q
u
a
t
:
:
Z
)
a=cos\frac{\theta}{2} (FQuat::W)\\ b=sin\frac{\theta}{2}x(FQuat::X)\\ c=sin\frac{\theta}{2}y(FQuat::Y)\\ d=sin\frac{\theta}{2}z(FQuat::Z)
a=cos2θ(FQuat::W)b=sin2θx(FQuat::X)c=sin2θy(FQuat::Y)d=sin2θz(FQuat::Z)
参考虚幻的轴角转化为四元数的代码:
template<typename T>
FORCEINLINE TQuat<T>::TQuat(TVector<T> Axis, T AngleRad)
{
const T half_a = 0.5f * AngleRad;
T s, c;
FMath::SinCos(&s, &c, half_a);
X = s * Axis.X;
Y = s * Axis.Y;
Z = s * Axis.Z;
W = c;
DiagnosticCheckNaN();
}
对于一个点 p ( x , y , z ) p(x,y,z) p(x,y,z),使其绕 n ⃗ \vec n n逆时针旋转 θ \theta θ
- 按照上文得出 q = c o s θ 2 + s i n θ 2 i + s i n θ 2 j + s i n θ 2 k q=cos\frac{\theta}{2}+sin\frac{\theta}{2}i+sin\frac{\theta}{2}j+sin\frac{\theta}{2}k q=cos2θ+sin2θi+sin2θj+sin2θk
- 将虚部记为 v ⃗ \vec v v,实部记为 w w w,即: q = w + v ⃗ q=w+\vec v q=w+v
- 使用公式(推理参考) p ′ = p + 2 w ( v × q ) + 2 v × ( v × q ) p' = p + 2w(v \times q) + 2v \times (v \times q) p′=p+2w(v×q)+2v×(v×q)
参考虚幻的旋转代码:
template<typename T>
FORCEINLINE TVector<T> TQuat<T>::RotateVector(TVector<T> V) const
{
const TVector<T> Q(X, Y, Z);
const TVector<T> TT = 2.f * TVector<T>::CrossProduct(Q, V);
const TVector<T> Result = V + (W * TT) + TVector<T>::CrossProduct(Q, TT);
return Result;
}
参考:
Some Notes on Unit Quaternions and Rotation
中文维基
四元数和旋转(Quaternion & rotation)