您不必使用矩阵,但需要使用那些正弦函数。这是一种将 3D 位置围绕某个任意轴旋转某个以度数指定的角度的方法:
// This is the 3D position that we want to rotate:
vec3 p = position.xyz;
// Specify the axis to rotate about:
float x = 0.0;
float y = 0.0;
float z = 1.0;
// Specify the angle in radians:
float angle = 90.0 * 3.14 / 180.0; // 90 degrees, CCW
vec3 q;
q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle))
+ p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle))
+ p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle));
q.y = p.x * (y*x * (1.0 - cos(angle)) - z * sin(angle))
+ p.y * (y*y * (1.0 - cos(angle)) + cos(angle))
+ p.z * (y*z * (1.0 - cos(angle)) + x * sin(angle));
q.z = p.x * (z*x * (1.0 - cos(angle)) + y * sin(angle))
+ p.y * (z*y * (1.0 - cos(angle)) - x * sin(angle))
+ p.z * (z*z * (1.0 - cos(angle)) + cos(angle));
gl_Position = vec4(q, 1.0);
如果您知道您正在围绕某个标准 x、y 或 z 轴旋转,则可以通过为该标准轴显式定义“算法”来大大简化它。
请注意我们在上面的代码中是如何绕 z 轴旋转的。例如,围绕 x 轴的旋转将是 (x,y,z) = (1,0,0)。您可以将变量设置为任何值,但这些值应该导致轴成为单位向量(如果这很重要的话。)
再一次,你不妨使用矩阵:
vec3 n = vec3(0.0, 0.0, 1.0); // the axis to rotate about
// Specify the rotation transformation matrix:
mat3 m = mat3(
n.x*n.x * (1.0f - cos(angle)) + cos(angle), // column 1 of row 1
n.x*n.y * (1.0f - cos(angle)) + n.z * sin(angle), // column 2 of row 1
n.x*n.z * (1.0f - cos(angle)) - n.y * sin(angle), // column 3 of row 1
n.y*n.x * (1.0f - cos(angle)) - n.z * sin(angle), // column 1 of row 2
n.y*n.y * (1.0f - cos(angle)) + cos(angle), // ...
n.y*n.z * (1.0f - cos(angle)) + n.x * sin(angle), // ...
n.z*n.x * (1.0f - cos(angle)) + n.y * sin(angle), // column 1 of row 3
n.z*n.y * (1.0f - cos(angle)) - n.x * sin(angle), // ...
n.z*n.z * (1.0f - cos(angle)) + cos(angle) // ...
);
// Apply the rotation to our 3D position:
vec3 q = m * p;
gl_Position = vec4(q, 1.0);
注意矩阵的元素是如何排列的,我们首先完成第一列,然后是第二列,依此类推;矩阵按列优先顺序排列。当您尝试将用数学符号编写的矩阵转换为代码中的数据类型时,这一点很重要。您基本上需要转置它(以对角翻转元素)才能在代码中使用它。此外,我们实质上是将左侧的矩阵与右侧的列向量相乘。
如果您需要一个 4×4 齐次矩阵,那么您只需在上述矩阵中添加一个额外的列和一行,这样新的最右边的列和最底端的行都将包含 [0 0 0 1]:
vec4 p = position.xyzw; // new dimension
vec3 n = ...; // same
mat4 m = mat4( // new dimension
...
0.0,
...
0.0,
...
0.0,
0.0,
0.0,
0.0,
1.0
);
vec4 q = m * p;
gl_Position = q;
再次,在应用旋转时注意乘法的顺序,这很重要,因为它会影响最终结果。乘法中发生的事情基本上是通过计算位置向量和矩阵中每一列的点积形成一个新向量;结果向量中的每个坐标都是原始向量和矩阵中单列的点积(参见第一个代码示例。)
q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle))
+ p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle))
+ p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle));
等同于:
q.x = dot(p, m[0]);
甚至可以自己组合矩阵:m = m*m;,这将导致逆时针旋转 180 度矩阵,具体取决于所使用的 angle。