c++ - 确定给定角度绕轴的旋转矩阵
问题描述
我一直在尝试理解矩阵和向量,并实现了 Rodrigue 的旋转公式来确定给定角度围绕轴的旋转矩阵。我有函数 Transform 调用函数 Rotate。
// initial values of eye ={0,0,7}
//initial values of up={0,1,0}
void Transform(float degrees, vec3& eye, vec3& up) {
vec3 axis = glm::cross(glm::normalize(eye), glm::normalize(up));
glm::normalize(axis);
mat3 resultRotate = rotate(degrees, axis);
eye = eye * resultRotate;
glm::normalize(eye);
up = up * resultRotate;`enter code here`
glm::normalize(up);
}
mat3 rotate(const float degrees, const vec3& axis) {
//Implement Rodrigue's axis-angle rotation formula
float radDegree = glm::radians(degrees);
float cosValue = cosf(radDegree);
float minusCos = 1 - cosValue;
float sinValue = sinf(radDegree);
float cartesianX = axis.x;
float cartesianY = axis.y;
float cartesianZ = axis.z;
mat3 myFinalResult = mat3(cosValue +(cartesianX*cartesianX*minusCos), ((cartesianX*cartesianY*minusCos)-(cartesianZ*sinValue)),((cartesianX*cartesianZ*minusCos)+(cartesianY*sinValue)),
((cartesianX*cartesianY*minusCos)+(cartesianZ*sinValue)), (cosValue+(cartesianY*cartesianY*minusCos)), ((cartesianY*cartesianZ*minusCos) - (cartesianX*sinValue)),
((cartesianX*cartesianZ*minusCos)-(cartesianY*sinValue)), ((cartesianY*cartesianZ*minusCos) + (cartesianX*sinValue)), ((cartesianZ*cartesianZ*minusCos) + cosValue));
return myFinalResult;
}
所有值、结果旋转矩阵和更改的向量都与 + 旋转角度的预期一样,但对于负角度是错误的,从那时起,具有级联效应,直到重新初始化所有向量。有人可以帮我解决问题吗?我不能使用任何内置函数,如 glm::rotate。
解决方案
我不使用Rodrigues_rotation_formula因为它需要在运行时计算方程组并且在更高维度上变得非常复杂。
相反,我使用轴对齐增量旋转以及4x4 同质变换矩阵,这些矩阵非常容易移植到更高维度,如4D 转子。
现在有局部和全局旋转。局部旋转将围绕您的矩阵坐标系统局部轴旋转,全局旋转将围绕世界(或主坐标系)旋转
你想要的是围绕一些point,axis
和创建一个变换矩阵angle
。要做到这一点:
创建一个变换矩阵
A
一个轴与旋转轴对齐,原点是旋转中心。要构造这样的矩阵,您需要 2 个垂直向量,这些向量很容易从叉积中获得。
围绕
A
与旋转轴对齐的局部轴旋转angle
A
通过轴对齐增量旋转的简单乘法,R
所以A*R;
A
还原旋转前的原始变换通过简单地乘以
A
结果的倒数,所以A*R*Inverse(A);
将此应用于
M
要旋转的矩阵也可以简单地将其乘以
M
:M*=A*R*Inverse(A);
就是这样......在这里你可以找到3D OBB近似函数:
template <class T> _mat4<T> rotate(_mat4<T> &m,T ang,_vec3<T> p0,_vec3<T> dp)
{
int i;
T c=cos(ang),s=sin(ang);
_vec3<T> x,y,z;
_mat4<T> a,_a,r=mat4(
1, 0, 0, 0,
0, c, s, 0,
0,-s, c, 0,
0, 0, 0, 1);
// basis vectors
x=normalize(dp); // axis of rotation
y=_vec3<T>(1,0,0); // any vector non parallel to x
if (fabs(dot(x,y))>0.75) y=_vec3<T>(0,1,0);
z=cross(x,y); // z is perpendicular to x,y
y=cross(z,x); // y is perpendicular to x,z
y=normalize(y);
z=normalize(z);
// feed the matrix
for (i=0;i<3;i++)
{
a[0][i]= x[i];
a[1][i]= y[i];
a[2][i]= z[i];
a[3][i]=p0[i];
a[i][3]=0;
} a[3][3]=1;
_a=inverse(a);
r=m*a*r*_a;
return r;
};
正是这样做的。哪里m
是要变换的原始矩阵(并返回旋转后的矩阵),ang
是 中的有符号角度[rad]
,p0
是旋转中心,是旋转dp
轴方向向量。
这种方法没有任何奇点或负角旋转的问题......
如果您想将此与 glm 或任何其他 GLSL (如数学)一起使用,只需将模板更改为您使用的模板,float,vec3,mat4
而不是T,_vec3<T>,mat4<T>
.
推荐阅读
- javascript - 子函数递归调用方法
- java - 有没有办法将关键侦听器添加到 Jtable 中的特定列?
- reactjs - 如何将 GridList 子组件添加为组件
- bash - 将 exec /bin/bash 添加到脚本以使其行为与 /bin/bash 完全一样?
- r - R函数来确定另一个应用程序是否正在运行
- python - 当我尝试在 pyqt5 中运行语音识别时,程序崩溃了
- javascript - 如何从输入值中查询包含文本字符串的所有文档?
- android - 删除字符时过滤器不更新列表
- java - java.util.stream.Collectors.toMap() 的值函数返回常量值
- java - 如何使用 Date today = new Date() 将日期时间从 java 设置为 sql;