四元数

我们使用四元数一般用来进行3D物体的旋转操作. 我们比较熟悉的是另外两种旋转的表示方法——矩阵旋转和欧拉旋转。

0.1. 矩阵旋转

矩阵旋转使用了一个4*4大小的矩阵来表示绕任意轴旋转的变换矩阵, 但是旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素, 而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费.

0.2. 欧拉角

而欧拉选择则是按照一定的坐标轴顺序(例如先x、再y、最后z)、每个轴旋转一定角度来变换坐标或向量,它实际上是一系列坐标轴旋转的组合, 但是这种方法是要按照一个固定的坐标轴的顺序旋转的,因此不同的顺序会造成不同的结果, 而且会造成万向节锁(Gimbal Lock)的现象, 由于万向节锁的存在,欧拉旋转无法实现球面平滑插值.

0.3. 四元数

但是用四元数就可以规避这些问题, 只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高, 而且可以提供平滑差值.

一个四元数可以表示为q = w + xi + yj + zk, 其中 $$ w^{2}+x^{2}+y^{2}+z^{2}=1 $$ 我们称之为单位四元数, 即四元数的模为1, 且 $$ i^{2} = j^{2} = k^{2} = ijk = -1 $$.

我们做一个简单的推导:
在平面空间内, 我们令p = a + bi为平面内的一个点. a为实部坐标, b为虚部坐标, 可以写成p=r cosα + r sinα. 我们将它旋转θ后, p' = r cos(α + θ) + r sin(α + θ) 然后和差化积得: 新坐标 x = a cos(θ) - b sin(θ) y = a sin(θ) + b cosθ, 定义q = cosθ + sinθ , 恰好qp的结果是 qp=(a cosθ − b sin θ + i (a sinθ + b * cosθ ), 由此我们可以推断出, q和p点乘可以表示为p旋转q以后的结果.

进一步推断, 在三维空间内, 我们将四元数写成$$ q = [s, \vec {v}]$$ s为实部, v表示三维空间.

$$ q_a = [S_a, \vec {a}] $$

$$ q_b = [S_b, \vec {b}] $$
我们令$$ q_a $$为纯四元数. && q_a &&点乘$$ q_b $$得, $$q_aq_b = [S_aS_b - \vec{a} \cdot \vec{b}, S_a \vec{b}+S_b \vec{a} + \vec{a} \times \vec{b}]$$

我们令 $$ q_b = [\cos \theta, \sin {\theta} \vec{b}] $$, 且$$ \vec{a} \cdot \vec{b} = 0 $$

举个简单的粒子, 我们让P(1,0,1)绕u(0,1,0)转90度, 最后旋转后的坐标应该是P’=(1, 0, -1), 我们计算一下: p=(0, P) q=(cos45, usin45), 求$$ p' = pqp^{-1} $$, 最后算完的值p' = (0, (1, 0, -1))

具体的四元数的计算这边不做详细的介绍, 下边主要介绍一下四元数在引擎中的使用.

    local pActor = world:FindActor(szActorName)
    ---获取Actor的旋转角度
    local quatRotation = pActor:GetActorRotation();

    ---现在我们控制Actor绕Actor的上方向旋转90度
    quatRotation:ConvertFromAxisAngle(pActor:GetActorUpVector(), 90)

    ---通过四元数朝向获取旋转轴和转向
    local vAxis, fAngle = quatRotation:ConvertToAxisAngle()

    ---通过欧拉角获取一个四元数
    quatRotation:ConvFromEulerAngle(fXAngle, fYAngle, fZAngle)
@Copyright © cosmos 2019 all right reserved,powered by Gitbook修订时间: 2021-04-12 18:28:17

results matching ""

    No results matching ""