网上有很多“绕任意轴的旋转矩阵”的文章,不过要么限定了所谓“任意轴”必须经过原点,要么只有推导没有结论。最近在完成图形学作业的时候正好用到了这个算法,通过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);
}

顺便说一下,Glenn Murray提供了一个网站[2],可以根据参数求出矩阵的值,并看到变换的效果。

参考资料:
[1] Rotation About an Arbitrary Axis in 3 Dimensions
[1] Twist and Shout!

» 转载请注明来源及链接:未来代码研究所

Related Posts:

Leave a Reply

World Line
Time Machine
Online Tools