围绕当前位置旋转矩阵的快速方法
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;
但我觉得应该有更有效的方法来做到这一点...
是的,我就是这样做的。但是一个细微的修正,颠倒 -T
和 T
:
的顺序
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;
如果我有一个矩阵,那么点 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;
但我觉得应该有更有效的方法来做到这一点...
是的,我就是这样做的。但是一个细微的修正,颠倒 -T
和 T
:
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;