网上有很多“绕任意轴的旋转矩阵”的文章,不过要么限定了所谓“任意轴”必须经过原点,要么只有推导没有结论。最近在完成图形学作业的时候正好用到了这个算法,通过Google娘找到了一篇名叫Glenn Murray的老外的文章,于是直接拿来用了。以下直接放结论,详细推导过程可以参考原文[1]。
算法的输入参数分别是旋转轴上的任意一点P(a,b,c),单位化后的旋转轴方向向量V(u,v,w),旋转角度θ。
矩阵推导过程
1、应用平移变换,使得变换后的旋转轴经过空间坐标原点。
2、应用绕z轴的旋转变换,使得变换后的旋转轴位于xz平面。
3、应用绕y轴的旋转变换,使得变换后的旋转轴与z轴重合。
4、应用绕z轴的θ度角的旋转变换。
5、应用步骤3的逆变换。
6、应用步骤2的逆变换。
7、应用步骤1的逆变换。
最终矩阵表达式
C++实现
// Returns the rotation matrix around the vector v placed at point p, rotate by angle a
Matrix4 rot_mat(const Point3& p, const Vector3& vv, const float t)
{
Vector3 vector = normalize(vv);
float u = vector.x;
float v = vector.y;
float w = vector.z;
float a = p.x;
float b = p.y;
float c = p.z;
return Matrix4(u*u+(v*v+w*w)*cos(t), u*v*(1-cos(t))-w*sin(t), u*w*(1-cos(t))+v*sin(t), (a*(v*v+w*w)-u*(b*v+c*w))*(1-cos(t))+(b*w-c*v)*sin(t),
u*v*(1-cos(t))+w*sin(t), v*v+(u*u+w*w)*cos(t), v*w*(1-cos(t))-u*sin(t), (b*(u*u+w*w)-v*(a*u+c*w))*(1-cos(t))+(c*u-a*w)*sin(t),
u*w*(1-cos(t))-v*sin(t), v*w*(1-cos(t))+u*sin(t), w*w+(u*u+v*v)*cos(t), (c*(u*u+v*v)-w*(a*u+b*v))*(1-cos(t))+(a*v-b*u)*sin(t),
0, 0, 0, 1);
}
Matrix4 rot_mat(const Point3& p, const Vector3& vv, const float t)
{
Vector3 vector = normalize(vv);
float u = vector.x;
float v = vector.y;
float w = vector.z;
float a = p.x;
float b = p.y;
float c = p.z;
return Matrix4(u*u+(v*v+w*w)*cos(t), u*v*(1-cos(t))-w*sin(t), u*w*(1-cos(t))+v*sin(t), (a*(v*v+w*w)-u*(b*v+c*w))*(1-cos(t))+(b*w-c*v)*sin(t),
u*v*(1-cos(t))+w*sin(t), v*v+(u*u+w*w)*cos(t), v*w*(1-cos(t))-u*sin(t), (b*(u*u+w*w)-v*(a*u+c*w))*(1-cos(t))+(c*u-a*w)*sin(t),
u*w*(1-cos(t))-v*sin(t), v*w*(1-cos(t))+u*sin(t), w*w+(u*u+v*v)*cos(t), (c*(u*u+v*v)-w*(a*u+b*v))*(1-cos(t))+(a*v-b*u)*sin(t),
0, 0, 0, 1);
}
顺便说一下,Glenn Murray提供了一个网站[2],可以根据参数求出矩阵的值,并看到变换的效果。
参考资料:
[1] Rotation About an Arbitrary Axis in 3 Dimensions
[1] Twist and Shout!
» 转载请注明来源及链接:未来代码研究所