与四元数的旋转

2021-06-03 23:00:17

四元数是4维复杂的数字,它有四个组件,其中三个是"想象中的" 部分。 $$ q = a + b \ textrm {i} + c \ textrm {j} + d \ textrm {k} $$ $$ q =(b,c,d,a)$$ $$ $$ \ textrm {i} ^ {2} = \ textrm {j} ^ {2} = \ textrm {k} ^ {2} = \ textrm {i} \ textrm {} \ textrm {j} \ textrm {k} = - 1 $$ typedef联合{float q [4]; struct {float x; 浮子y; 浮子Z; 浮动w; };}四元数; 四个组件通常是有序的\(w,x,y,z \),但我喜欢在最后放置\(w \)。 四元数基本上是4维向量,因此它具有幅度(或规范或长度): $$ || q || = \ Sqrt {x ^ {2} + y ^ {2} + z ^ {2} + w ^ {2} + w ^ {2}} $$$$$$$$$$$一种单位四分之一(凌乱的四元数)(1 \) )表示在3D空间中的旋转。 几何上,我们还可以考虑\((0,0,0,-1)\),因为它对应于没有旋转。 缩放四元数正在将每个组件乘以实数(标量):

四元数乘法ISN' t换向(\(q_ {1} .q_ {2} \ ne q_ {2} .q_ {1} \))。如果我们想应用旋转\(q_ {1} \)那么旋转\(q_ {2} \),所得到的旋转\(q_ {3})是:

$$ Q_ {3} = q_ {2} .q_ {1} $$ $$ q_ {1} = a + b \ textrm {i} + c \ textrm {j} + d \ textrm {k} $$$ $ q_ {2} = e + f \ textrm {i} + g \ textrm {j} + h \ textrm {k} $$$$$ \ begin {sealth *} q_ {1} .q_ {2} =(ae -bf-cg-dh)+(af + be + ch-dg)\ textrm {i} + \\(ag-bh + ce + df)\ textrm {j} +(ah + bg-cf + de)\ textrm {k} \ neg {align *} $$四半管quat_mul(四元数a,四元数b){return(四元数){aw * bx + ax * bw + ay * bz - az * by,aw * by - ax * bz + ay * bw + az * bx,aw * bz + ax * by - ay * bx + az * bw,aw * bw - ax * bx - ay * by - az * bz};}

我们使用四元数而不是欧拉角度表示旋转几个原因:

我们仅使用四元数表示对象的方向,然后我们将其乘以另一个四元数来旋转它。

然而,直接以四元轴形式写入旋转.T真的直观,我们所做的是将欧拉角转换为四元数,然后使用它来旋转。

如果我们在Zyx(偏航 - > roll; roll; roll,我们可以选择任何顺序,但必须保持一致),我们可以将它转换为如下四元数:

$$ q = \ begin {bmatrix} \ sin(x / 2)\ cos(y / 2)\ cos(z / 2) - \ cos(x / 2)\ sin(y / 2)\ sin(z / 2)\\\ cos(x / 2)\ sin(y / 2)\ cos(z / 2)+ \ sin(x / 2)\ cos(y / 2)\ sin(z / 2)\\\ cos(x / 2)\ cos(y / 2)\ sin(z / 2) - \ sin(x / 2)\ sin(y / 2)\ cos(z / 2)\\ cos(x / 2 )\ cos(y / 2)\ cos(z / 2)+ \ sin(x / 2)\ sin(y / 2)\ sin(z / 2)\ end {bmatrix} $$ typedef联盟{float v [ 3]; struct {float x;浮子y;浮子Z; Vector3;四元数euler_to_quat(Vector3 E){float cx = cos(e.x / 2); float sx = sin(e.x / 2); Float Cy = COS(例如/ 2);浮子sy = sin(例如/ 2); Float CZ = COS(E.Z / 2); float sz = sin(e.z / 2);返回(季芯){SX * CY * CZ - CX * SY * SZ,CX * SZ,CX * CY * SZ - SX * SY * CZ,CX * CY * CZ + SX * SY * sz};}

转换obj; obj.position =(vector3){0,0,0}; obj.scale =(丝锥){1,1,1,1}; obj.rotation = quat_id(); //最初是我们的对象ISN' t旋转//通过y anderobj.rotation = quat_mul(euler_to_quat(euler_to_quat(euler_to_quat((vector3){0,pi / 4,0}),obj.rootation)旋转对象。 //通过PI / 4再次旋转,使其围绕Yobj.rotation = Quat_mul(euler_to_quat(euler_to_quat((vector3){0,pi / 4,0}),obj.rotation);

在进行3D渲染时,我们通常将MVP(模型视图投影)矩阵传递给着色器,以便在场景中查看我们的对象:

$$ \ textit {mvp} = m _ {\ textit {projection}}。m _ {\ textit {view}}。m _ {\ textit {model}} $$ $$ m _ {\ textit {model}} = m _ {\ Textit {scale}}。m _ {\ textit {rotate}}。m _ {\ textit {translate}} $$ $$ q =(x,y,z,w)$$$$ m_ {\ textit {rotate}} = \ begin {bmatrix} 1-2yy-2zz&& 2xy-2zw&& 2xz + 2yw&& 0 \\ 2xy + 2zw&& 1-2xx-2zz&& 2YZ-2XW&& 0 \\ 2xz-2yw&& 2YZ + 2XW&& 1-2xx-2yy&& 0 \\ 0&& 0&& 0&& 1 \ END {BMATRIX} $$图形API(如OPENGL)通常表示列在列 - 主要表示法中的内存中的矩阵,因此我们必须在代码中转换矩阵:

typedef联合{float m [16]; struct {float m00;浮子M10;浮动M20;浮子M30; float m01;浮子M11; float m21; float m31;浮动M02;浮动m12; float m22;浮动M32;浮动M03;浮子M13;浮子M23;浮子M33; mat4; mat4 rotate_3d_matrix(四元管q){float xx = q.x * q.x; float yy = q.y * q.y; float zz = q.z * q.z;返回(MAT4){1-2 * YY-2 * ZZ,2 * QX * Q.Y + 2 * QZ * QW,2 * QX * QZ-2 * QY * QW,0,2 * QX * QY-2 * qz * qw,1-2 * xx-2 * zz,2 * qy * q.z + 2 * qx * qw,0,2 * qx * q.z + 2 * qy * qw,2 * qy * qz -2 * qx * qw,1-2 * xx-2 * yy,0,0,0,0,1};}

$$ Q ^ {*} = ab \ textrm {i} -c \ textrm {j} -d \ textrm {k} $$$ =(q \)的倒数,表示\(q ^ { - 1} \),缀合物除以幅度平方:

$$ Q ^ { - 1} = \ frac {q ^ {*}} {|| q || ^ {2}} $$四半管quat_inverse(quaternion q){float m = quat_magnitude(q);如果(m == 0)返回(四元管){0,0,0,0}; //避免分割0 m * = m;返回(四元数){ - q.x / m,-q.y / m,-q.z / m,q.w / m};}

对于单位四元数,缀合物等于逆。通过其逆率在身份十二段中将四元度乘以:

$$ QQ ^ { - 1} =(0,0,0,1)$$$$ \(q_ {1} \)和\(q_ {2} \)的差异是另一个四元数\(q_ {3 } \)从\(q_ {1} \)旋转到\(q_ {2} \):

$$ Q_ {3} = q_ {1} ^ { - 1} .q_ {2} $$ exthernention and quaternion won' t非常有用,但我们将使用它们来计算其他稍后函数。

给定四元管\(q =(x,y,z,w)\)及其矢量部分\(v =(x,y,z)\),那个四元数的指数也是四元数,它&#39 ;由这个公式给出:

$$ \ exp(q)= \ exp(w)\ begin {pmatrix} \ frac {v_ {x}} {|| v ||} \ sin(|| v ||)\\\ frac {v_ {y }} {|| v ||} \ sin(|| v ||)\\\ frac {v_ {z}} {|| v ||} \ sin(|| v ||)\\\ cos(| | v ||)\ end {pmatrix} $$四半管quat_exp(四元数q){vector3 v =(vector3){qx,qy,qz}; float v_m = vector3_magnitude(v); Vector3 v_n = Vector3_normalize(v); float sin_v = sin(v_m); float exp_w = exp(q.w);返回(四元数){v_n.x * sin_v * exp_w,v_n.y * sin_v * exp_w,v_n.z * sin_v * exp_w,cos(v_m)* exp_w};}

四元数的对数也是四元数,由此公式给出:

$$$ \ log(q)= \ begin {pmatrix} \ frac {v_ {x}} {|| v ||} \ arccos(\ frac {w} {|| q ||})\\\ frac {v_ {y}} {|| v ||} \ arccos(\ frac {w} {|| q ||})\\\ frac {v_ {z}} {|| v ||} \ arccos(\ frac { w}} {|| q ||})\\\ log(|| Vector3 v_n = Vector3_normalize(v); float m = quat_magnitude(q); float a = acos(q.w / m);返回(四元数){v_n.x * a,v_n.y * a,v_n.z * a,log(m)};}

向权力提高四元素导致该四季度的分数或倍数。 \(Q ^ {2} \)表示\(q \)的旋转的两倍,\(q ^ {\ frac {1} {2}}表示旋转的一半。

$$ q ^ {n} = \ exp(n \ log(q))$$可以说是四元数最重要的优势之一," slerp"代表球形线性插值。它' sa函数,即占用三个参数:四元数\(q_ {1} \),四元数\(q_ {2} \)和从\(0 \)的插值参数\(t \) \(1 \)。它根据\(t \)的值给出了中间旋转。

$$ \ textrm {slerp}(q_ {1},q_ {2},t)= q_ {1}(q_ {1} ^ { - 1} q_ {2})^ {t} $$四半管quat_slerp(四元数Q1,四元数Q2,浮点T){T = T< 0? 0:T; t = t> 1? 1:T;返回quat_mul(q1,quat_pow(quat_mul(quat_inverse(q1),q2),t));}

这是一个动画,显示从欧拉角度划分的立方体((0,\ frac {5 \ pi} {4},\ frac {\ pi} {4})到\((0,0,0)\ ):

转换obj; quaternion start_rotation = euler_to_quat((Vector3){0,5 * pi / 4,pi / 4}); quaternion target_rotation = euler_to_quat((Vector3){0,0,0})obj.rotation = start_rotation; float t = 0; //主循环时(1){... obj.rotation = quat_slerp(start_rotation,target_rootation,t); t + = delta_time; ...}