四元数[转]

最近做camera 的 AI,需要对四元数,欧拉角等要有一定的了解,把前面学习的整理了一下:

1。四元数的优势: 三维空间的旋转完全可以由4元数来胜任。传统意义上需要3×3矩阵来进行向量的旋转(4x4矩阵的第四列表示平移)。所以四元数更节省空间,运算速度更快。既然四元数能方便的表示3D旋转,那么对他们进行插值就能产生平滑的旋转效果。

劣势可能是比较抽象,不大好理解。而且据说顶点变换还是矩阵效率更高(涉及到平移)。

2。四元数的物理意义:

Q( x, y, z, w)来表示向量 绕轴 A(ax, ay,az) 旋转alpha

则: x = sin(alpha/2)*ax;

          y =   sin(alpha/2)*ay;

          z =  sin(alpha/2)*az;

          w = cos(alpha/2);

 

3。四元素的数学意义:

我们知道 复数的表示为 a+bi; 其中i*i = -1;

四元数 q = w + xi + yi +zi;

复数的运算法则为四元数的数学运算提供了规则基础。比如说乘法,加法等。

4。四元数和矩阵间的转换:

QX =0; QY=1;QZ=2;QW=3;

void quat_ConvertFromMatrix(float *pQuat, const float mat[4][4]) { float diag, s; int i, j, k;

diag = mat[0][0] + mat[1][1] + mat[2][2];

if(diag < -0.999f ) {   i = QX;   if( mat[QY][QY] > mat[QX][QX] )    i = QY;   if( mat[QZ][QZ] > mat[i][i] )    i = QZ;     j = g_QNext[i];   k = g_QNext[j];

  s = ltsqrtf( mat[i][i] - ( mat[j][j] + mat[k][k] ) + /*mat[3][3]*/ 1.0f );

  pQuat[i] = s * 0.5f;   s = 0.5f / s;   pQuat[QW] = ( mat[k][j] - mat[j][k] ) * s;   pQuat[j] = ( mat[j][i] + mat[i][j] ) * s;   pQuat[k] = ( mat[k][i] + mat[i][k] ) * s;   return; }

s = ltsqrtf( diag + /*mat[3][3]*/ 1.0f ); pQuat[3] = s * 0.5f; s = 0.5f / s;

pQuat[0] = (mat[2][1] - mat[1][2]) * s; pQuat[1] = (mat[0][2] - mat[2][0]) * s; pQuat[2] = (mat[1][0] - mat[0][1]) * s; }

 

void quat_ConvertToMatrix(const float *pQuat, float mat[4][4]) { float s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;

 

/*!   get the values for matrix calcuation. */ s = 2.0f / ((pQuat[0] * pQuat[0]) + (pQuat[1] * pQuat[1]) +   (pQuat[2] * pQuat[2]) + (pQuat[3] * pQuat[3]));

xs = pQuat[0] * s; ys = pQuat[1] * s; zs = pQuat[2] * s;

wx = pQuat[3] * xs; wy = pQuat[3] * ys; wz = pQuat[3] * zs;

xx = pQuat[0] * xs; xy = pQuat[0] * ys; xz = pQuat[0] * zs;

yy = pQuat[1] * ys; yz = pQuat[1] * zs;

zz = pQuat[2] * zs;

 

/*!   Fill in matrix

*/ mat[0][0] = 1.0f - (yy + zz); mat[0][1] = xy - wz; mat[0][2] = xz + wy; mat[1][0] = xy + wz; mat[1][1] = 1.0f - (xx + zz); mat[1][2] = yz - wx;

mat[2][0] = xz - wy; mat[2][1] = yz + wx; mat[2][2] = 1.0f - (xx + yy);

mat[0][3] = mat[1][3] = mat[2][3] = mat[3][0] = mat[3][1] = mat[3][2] = 0.0f; mat[3][3] = 1.0f; } 具体推倒过程可以参考相关文献。

5。四元数插值: 有很多插值方法,比如线性,球形,样条插值等;

lerp (t;,q0,q1) = (1-t)q0 + tq1 ;//快速,但动画不平滑,需要归一化 / ||(1-t)q0 + tq1||;

slerp( t;, q0,q1) = [q0 *sin(thata(1-thata)) + q1sin(thata*t)] / sin(thata); //平滑,归一化;

thata 为q0 q1夹角。q0 dot q1 = cos(thata);

相关代码:

void quat_Slerp(float *pDest, const float *pQ1, const float *pQ2, float t) { float rot1q[4]; float omega, cosom, oosinom; float scalerot0, scalerot1;

/*!   Calculate the cosine

*/ cosom = pQ1[0]*pQ2[0] + pQ1[1]*pQ2[1] + pQ1[2]*pQ2[2] + pQ1[3]*pQ2[3];

/*!   adjust signs if necessary

*/ if(cosom < 0.0f) {   cosom = -cosom;   rot1q[0] = -pQ2[0];   rot1q[1] = -pQ2[1];   rot1q[2] = -pQ2[2];   rot1q[3] = -pQ2[3]; } else  {   rot1q[0] = pQ2[0];   rot1q[1] = pQ2[1];   rot1q[2] = pQ2[2];   rot1q[3] = pQ2[3]; }

/*!   calculate interpolating coeffs

*/ if ( (1.0f - cosom) > 0.0001f ) { /*!    standard case

*/   omega   = ltacosf(cosom);   oosinom = 1.0f / ltsinf(omega);   scalerot0 = ltsinf((1.f - t) * omega) * oosinom;   scalerot1 = ltsinf(t * omega) * oosinom; } else { /*!    rot0 and rot1 very close - just do linear interp.

*/   scalerot0 = 1.0f - t;   scalerot1 = t; }

//! build the new quarternion pDest[0] = (scalerot0 * pQ1[0] + scalerot1 * rot1q[0]); pDest[1] = (scalerot0 * pQ1[1] + scalerot1 * rot1q[1]); pDest[2] = (scalerot0 * pQ1[2] + scalerot1 * rot1q[2]); pDest[3] = (scalerot0 * pQ1[3] + scalerot1 * rot1q[3]); }

 

参考文献:

游戏编程精粹

LithTech引擎

原文地址http://blog.youkuaiyun.com/hziee_/article/details/1630116

四元数(Quaternion)是一种用于进行三维空间旋的表示方法。与欧拉角(Euler angles)相比,四元数具有很多优点,例如不会出现万向锁问题,旋计算更加高效等等。 四元数可以表示为:q = w + xi + yj + zk,其中w, x, y, z是实数,i, j, k是虚数单位,满足以下关系: i^2 = j^2 = k^2 = i*j*k = -1 四元数的乘法可以表示为:q1 * q2 = (w1w2 - x1x2 - y1y2 - z1z2) + (w1x2 + x1w2 + y1z2 - z1y2)i + (w1y2 - x1z2 + y1w2 + z1x2)j + (w1z2 + x1y2 - y1x2 + z1w2)k。 通过四元数,我们可以将一个向量绕任意轴旋。具体来说,假设我们要将一个向量v绕一个单位向量n旋θ度,那么旋后的向量v'可以表示为: v' = q * v * q^-1 其中q是一个表示旋四元数,q^-1是q的逆元,具体计算方法可以使用以下公式: q = cos(θ/2) + sin(θ/2) * (nx*i + ny*j + nz*k) q^-1 = cos(θ/2) - sin(θ/2) * (nx*i + ny*j + nz*k) 将v代入上述公式,我们可以得到旋后的向量v'。由于四元数的乘法和逆元计算比较复杂,因此可以使用现成的数学库来实现四元数。例如,在Python中可以使用numpy库的Quaternion类来进行四元数。以下是一个简单的例子: ``` import numpy as np # 定义旋轴和旋角度 axis = [1, 0, 0] angle = np.pi / 2 # 创建四元数 q = np.quaternion(np.cos(angle / 2), *(np.sin(angle / 2) * np.array(axis))) # 定义要旋的向量 v = np.array([1, 0, 0]) # 进行旋 v_rotated = q * v * q.conj() # 输出旋后的向量 print(v_rotated) ``` 输出结果为:[1.+0.j, 0.+1.j, 0.+0.j],表示向量v绕x轴旋90度后的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值