围绕当前位置旋转矩阵的快速方法

fast way to rotate a matrix about its current position

如果我有一个矩阵,那么点 O(0,0,0) 将被转换为某个点 P(x, y, z)。因此,围绕其当前位置旋转矩阵实际上是将矩阵乘以关于 P 的旋转矩阵。

所以我想要一个像这样的函数:

mat4 rotate(mat4 matrix, vec3 axis, float angle);

我目前的想法是:

vec4 p = {0, 0, 0, 1};

p = p * matrix;

generate translation matrix T, from point p

generate rotation matrix R, from axis and angle

return matrix * T * R * -T;

但我觉得应该有更有效的方法来做到这一点...

是的,我就是这样做的。但是一个细微的修正,颠倒 -TT:

的顺序
  return matrix * -T * R * T

你想'undo'matrix的平移原点,然后旋转,then重新做翻译。如果你拿一个传统的 scale/rotate/translate 矩阵 (S * R2 * T) 为例,将它展开,那么你会更容易看到:

  (S * R2 * T) * -T * R * T

正在做你想做的事。

编辑:关于效率,完全取决于使用情况。不,这不是 'great' -- 通常您有更多关于 matrix 的信息,这将使您能够以一种较少迂回的方式来执行此操作。例如,如果矩阵是从上面的 S * R * T 构建的,显然我们可以简单地首先改变矩阵的构建方式——S * R2 * R * T,将旋转注入它应该在的位置而不必'undo' 任何东西。

但是除非你在 10K+ 矩阵上实时执行此操作 每次都需要重新计算,否则这应该不是问题。

如果 matrix 来自未知来源并且您需要根据 post-事实对其进行修改,确实没有其他选择。

通常变换矩阵 (OpenGL/glsl/glm) 定义如下:

mat4 m44 = mat4(
    vec4( Xx, Xy, Xz, 0.0),   // x-axis
    vec4( Yx, Xy, Yz, 0.0),   // y-axis
    vec4( Zx  Zy  Zz, 0.0),   // z-axis
    vec4( Tx, Ty, Tz, 1.0) ); // translation

翻译矩阵如下所示:

mat4 translate = mat4(
    vec4( 0.0, 0.0, 0.0, 0.0),
    vec4( 0.0, 0.0, 0.0, 0.0),   
    vec4( 0.0  0.0  0.0, 0.0),  
    vec4( Tx,  Ty,  Tz,  1.0) );

旋转矩阵(例如围绕 Y 轴)如下所示:

float angle;
mat4 rotate = mat4(
    vec4( cos(angle),  0, sin(angle), 0 ),
    vec4( 0,           1, 0,          0 ),
    vec4( -sin(angle), 0, cos(angle), 0 ),
    vec4( 0,           0, 0,          1 ) )

矩阵乘法 C = A * B 的工作原理如下:

mat4 A, B, C;

// C = A * B
for ( int k = 0; k < 4; ++ k )
    for ( int j = 0; j < 4; ++ j )
        C[k][j] = A[0][l] * B[k][0] + A[1][j] * B[k][1] + A[2][j] * B[k][2] +  A[3][j] * B[k][3];

这意味着translate * rotate的结果是:

mat4 m = mat4(
    vec4( cos(angle),  0,  sin(angle), 0 ),
    vec4( 0,           1,  0,          0 ),
    vec4( -sin(angle), 0,  cos(angle), 0 ),
    vec4( tx,          ty, tz,         1 ) );


这意味着如果您想围绕原点旋转矩阵 M,则必须将矩阵拆分为 "oriantation" 矩阵和 "translation" 矩阵。旋转方向矩阵并再次添加平移矩阵:

mat4 M, R;

float Tx = M[3][0];
float Ty = M[3][1];
float Tz = M[3][2];

M[3][0] = 0.0; M[3][1] = 0.0; M[3][2] = 0.0;

mat4 MR = R * M;
MR[3][0] = Tx; MR[3][1] = Ty; M[3][2] = Tz;