我正在尝试使用带有着色器的 PyOpenGL 围绕多个轴旋转对象。因为没有像旧 OpenGL 中那样的 glRotatef(),所以我使用 4x4 旋转矩阵。然而,由于矩阵乘法不可交换,因此它建立了这种父子关系,其中一个轴独立旋转(父轴),另一个轴基于第一个轴(子轴)旋转。我对矩阵不是很熟悉,我刚刚开始 AP 预计算,还没有接触到矩阵,但据我所知,如果不建立这种关系,就无法将旋转矩阵相乘。
这是程序示例。
model1 = np.array([[1, 0, 0, 0],
[0, cos(player_rotation_x), sin(player_rotation_x), 0],
[0, -sin(player_rotation_x), cos(player_rotation_x), 0],
[0, 0, 0, 1]
]) @ np.array([[cos(-player_rotation_z), -sin(-player_rotation_z), 0, 0],
[sin(-player_rotation_z), cos(-player_rotation_z), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
]) @ np.array([[cos(player_rotation_y), 0, -sin(player_rotation_y), 0],
[0, 1, 0, 0],
[sin(player_rotation_y), 0, cos(player_rotation_y), 0],
[0, 0, 0, 1]])
这建立了从 x 到 y 的层次结构。
这是我尝试使用着色器而不是固定功能管道重新创建的程序示例。
rotation_matrix = (GLfloat * 16)(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
while True:
glPushMatrix()
glLoadIdentity()
glRotatef(-player_rotation_x, 1, 0, 0)
glRotatef(-player_rotation_y, 0, 1, 0)
glMultMatrixf(rotation_matrix)
glGetFloatv(GL_MODELVIEW_MATRIX, rotation_matrix)
glPopMatrix()
矩阵乘法不是可交换的。当矩阵相乘时,顺序很重要,这是一个数学事实。您问题中的两个代码片段之间存在很大差异。虽然第一个基于旋转创建了一个全新的矩阵,
model = rX * rZ * rY
第二个(旧版 OpenGL)通过将当前模型矩阵与新旋转连接来更新当前模型矩阵
model = rX * rY * model
不要对角度求和,而是逐步更改模型转换,就像旧版 OpenGL 代码中的情况一样。使用单位矩阵初始化模型矩阵:
model = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
根据新的增量旋转角度计算旋转矩阵并将其与模型矩阵连接:
rX = np.array([[1, 0, 0, 0],
[0, cos(player_rotation_x), sin(player_rotation_x), 0],
[0, -sin(player_rotation_x), cos(player_rotation_x), 0],
[0, 0, 0, 1]])
rZ = np.array([[cos(-player_rotation_z), -sin(-player_rotation_z), 0, 0],
[sin(-player_rotation_z), cos(-player_rotation_z), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
rY = np.array([[cos(player_rotation_y), 0, -sin(player_rotation_y), 0],
[0, 1, 0, 0],
[sin(player_rotation_y), 0, cos(player_rotation_y), 0],
[0, 0, 0, 1]])
model = rX @ rZ @ rY @ model
您可以使用 PyGLM 或 Pyrr 简化该代码。这是使用 PyGlm 实现的示例。
导入PyGlm
import glm
初始化矩阵
model = glm.mat4(1)
创建旋转矩阵并与模型矩阵相乘:
rotation = glm.rotate(glm.mat4(1), player_rotation_x, glm.vec3(1, 0, 0))
glm.rotate(rotation, player_rotation_z, glm.vec3(0, 0, 1)) *
glm.rotate(rotation, player_rotation_y, glm.vec3(0, 1, 0)) *
model = rotation * model;