博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
四元数
阅读量:4499 次
发布时间:2019-06-08

本文共 3175 字,大约阅读时间需要 10 分钟。

最近做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] ) + 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 + 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;

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;

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;

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

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];
}

if ( (1.0f - cosom) > 0.0001f )
{
omega = ltacosf(cosom);
oosinom = 1.0f / ltsinf(omega);
scalerot0 = ltsinf((1.f - t) * omega) * oosinom;
scalerot1 = ltsinf(t * omega) * oosinom;
}
else
{
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]);
}

转载于:https://www.cnblogs.com/stardasha/p/3461569.html

你可能感兴趣的文章
解决IOS safari下滑动的“橡皮筋”效果
查看>>
asp.net 得到一个文件夹下的所有文件夹及子文件夹名,得到所有文件名,文件大小,文件夹大小...
查看>>
从keystore(jks)文件中提取私钥
查看>>
调整数组顺序使奇数位于偶数前面
查看>>
css3的3D和2D
查看>>
简单的响应式布局的实现
查看>>
jQuery(属性操作)
查看>>
Python之路【第九篇】:Python面向对象
查看>>
background和background-image一点小区别
查看>>
ASCII码对照表
查看>>
HackerRank "Training the army" - Max Flow
查看>>
jquery next()方法
查看>>
深入剖析js命名空间函数namespace
查看>>
SQLHelper
查看>>
用标准Struts2+mvc写的用户管理
查看>>
Cocos2d-x 3.0 编译出错 解决 error: expected &#39;;&#39; at end of member declaration
查看>>
Ubuntu12.04下载Repo
查看>>
python基础教程_学习笔记10:异常
查看>>
MATLAB——scatter的简单应用
查看>>
linux下复制粘贴快捷键
查看>>