四元数[转]

最近做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.csdn.net/hziee_/article/details/1630116

转载于:https://www.cnblogs.com/CoolSummer/articles/2784636.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值