我需要从 openGL 旋转矩阵中获取一些数据。我需要获得等效的欧拉角(已经做过),等效的四元数(做过,但只是从互联网上复制的)和等效的轴角。
我不知道旋转矩阵是否可以表示为围绕某个向量的某个角度的单次旋转。这些是等价的吗?如果是,我怎样才能从另一个那里获得一个?
另外,我想更好地理解四元数的含义以及旋转矩阵的内部。我应该去哪里了解这个?
我需要从 openGL 旋转矩阵中获取一些数据。我需要获得等效的欧拉角(已经做过),等效的四元数(做过,但只是从互联网上复制的)和等效的轴角。
我不知道旋转矩阵是否可以表示为围绕某个向量的某个角度的单次旋转。这些是等价的吗?如果是,我怎样才能从另一个那里获得一个?
另外,我想更好地理解四元数的含义以及旋转矩阵的内部。我应该去哪里了解这个?
是的,任何旋转矩阵/单位四元数都相当于围绕单轴旋转。如果我们称这个轴n
和角度,theta
那么这个旋转的四元数是:
[n * sin(theta / 2) cos(theta / 2)]
acos
在四元数的元素上重构这个使用w
得到theta / 2
. 之后,theta
您可以划分x
,y
和z
组件sin(theta / 2)
来重建轴。
这是一个将 3x3 矩阵转换为轴、角度的函数(使用 quatention,所以也许有一种更有效的方法可以绕过该步骤)。
void axis_angle_from_mat3(float r_axis[3], float *r_angle, float mat[3][3])
{
float q[4];
/* -------------------------------------------------------------------- */
/* matrix to quaternion */
double tr, s;
float tmat[3][3];
/* work on a copy */
memcpy(tmat, mat, sizeof(tmat));
/* normalize the matrix */
int i;
for (i = 0; i < 3; i++) {
float d = (tmat[i][0] * tmat[i][0] + tmat[i][1] * tmat[i][1] + tmat[i][2] * tmat[i][2]);
if (d > 1.0e-35f) {
d = sqrtf(d);
tmat[i][0] /= d;
tmat[i][1] /= d;
tmat[i][2] /= d;
}
else {
tmat[i][0] = 0.0f;
tmat[i][1] = 0.0f;
tmat[i][2] = 0.0f;
d = 0.0f;
}
}
tr = 0.25 * (double)(1.0f + tmat[0][0] + tmat[1][1] + tmat[2][2]);
if (tr > (double)1e-4f) {
s = sqrt(tr);
q[0] = (float)s;
s = 1.0 / (4.0 * s);
q[1] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
q[2] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
q[3] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
}
else {
if (tmat[0][0] > tmat[1][1] && tmat[0][0] > tmat[2][2]) {
s = 2.0f * sqrtf(1.0f + tmat[0][0] - tmat[1][1] - tmat[2][2]);
q[1] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
q[2] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
q[3] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
}
else if (tmat[1][1] > tmat[2][2]) {
s = 2.0f * sqrtf(1.0f + tmat[1][1] - tmat[0][0] - tmat[2][2]);
q[2] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
q[1] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
q[3] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
}
else {
s = 2.0f * sqrtf(1.0f + tmat[2][2] - tmat[0][0] - tmat[1][1]);
q[3] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
q[1] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
q[2] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
}
}
/* normalize the quat */
float len;
len = sqrtf(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
if (len != 0.0f) {
q[0] /= len;
q[1] /= len;
q[2] /= len;
q[3] /= len;
}
else {
q[1] = 1.0f;
q[0] = q[2] = q[3] = 0.0f;
}
/* -------------------------------------------------------------------- */
/* quaternion to axis angle */
float ha, si;
ha = acosf(q[0]);
si = sinf(ha);
*r_angle = ha * 2;
if (fabsf(si) < FLT_EPSILON)
si = 1.0f;
r_axis[0] = q[1] / si;
r_axis[1] = q[2] / si;
r_axis[2] = q[3] / si;
}