我一直在尝试使用opengl编写3d rubiks多维数据集,但是像许多其他示例一样,在理解每个具有自己的矩阵并使用glMultMatrixf()的概念时遇到了麻烦。相反,当我旋转一个立方体的侧面时,我一直在切换每个单独的立方体的颜色。但是,当我向右旋转然后向上旋转颜色时,有时会引起问题。我想知道是否有可能通过切换颜色来做到这一点,是否可以帮助我调试问题。谢谢!
例如,现在,如果我先执行turn_x然后执行turn_y,则在我切换多维数据集上的颜色时,颜色将无法正确显示。有没有办法更改lr和ud功能,以便可以正确切换颜色?任何帮助将不胜感激!
主要:
dim = 3
cube = []
for x in range(-1, 2):
for y in range(-1, 2):
for z in range(-1, 2):
matrix = np.matrix([[x, 0, 0], [0, y, 0], [0, 0, z]])
cube.append(Piece(x, y, z, matrix))
def turn_x(direction):
trans_matrix = np.matrix([[0, 1], [-1, 0]])
for i in range(len(cube)):
block = cube[i]
if block.x == direction:
new_point = trans_matrix * np.matrix([[block.y], [block.z]])
block.update(block.x, new_point.item(0), new_point.item(1))
block.lr(direction)
def turn_y(direction):
trans_matrix = np.matrix([[0, 1], [-1, 0]])
for i in range(len(cube)):
block = cube[i]
if block.y == direction:
new_point = trans_matrix * np.matrix([[block.x], [block.z]])
block.update(new_point.item(0), block.y, new_point.item(1))
block.ud(direction)
def main():
pygame.init()
display = (1200, 1000)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
gluPerspective(45, (display[0] / display[1]), 0.1, 50)
glClearColor(0.6, 0.6, 0.6, 0)
glTranslatef(0.0, 0.0, -20)
glRotatef(45, 1, 1, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_3:
turn_x(1)
if event.key == pygame.K_5:
turn_y(1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
for c in cube:
c.draw()
pygame.display.flip()
pygame.time.wait(10)
main()
件:
class Piece:
def __init__(self, x, y, z, position):
self.x = x
self.y = y
self.z = z
self.len = 0.5
self.v = [
(self.x - self.len, self.y - self.len, self.z - self.len),
(self.x + self.len, self.y - self.len, self.z - self.len),
(self.x + self.len, self.y + self.len, self.z - self.len),
(self.x - self.len, self.y + self.len, self.z - self.len),
(self.x - self.len, self.y - self.len, self.z + self.len),
(self.x + self.len, self.y - self.len, self.z + self.len),
(self.x + self.len, self.y + self.len, self.z + self.len),
(self.x - self.len, self.y + self.len, self.z + self.len),
]
self.edges = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6),
(6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)]
self.surfaces = [(0, 1, 2, 3), (5, 4, 7, 6), (4, 0, 3, 7), (1, 5, 6, 2),
(4, 5, 1, 0), (3, 2, 6, 7)]
self.colors = [ # blue
(0, 0, 1),
# green
(0, 1, 0),
# orange
(1, 0.5, 0.1),
# red
(1, 0, 0),
# yellow
(1, 1, 0),
# white
(1, 1, 1)]
self.matrix = position
def lr(self, dir):
color_ind = []
if dir == -1:
color_ind = [4, 5, 2, 3, 1, 0]
else:
color_ind = [5, 4, 2, 3, 0, 1]
new_colors = []
for i in color_ind:
new_colors.append(self.colors[i])
self.colors = new_colors
def ud(self, dir):
color_ind = []
if dir == 1:
color_ind = [2, 3, 1, 0, 4, 5]
else:
color_ind = [3, 2, 0, 1, 4, 5]
new_colors = []
for i in color_ind:
new_colors.append(self.colors[i])
self.colors = new_colors
def update(self, x, y, z):
self.matrix = np.matrix([[x, 0, 0], [0, y, 0], [0, 0, z]])
print(self.matrix)
self.x = x
self.y = y
self.z = z
self.update_vertices()
def update_vertices(self):
self.v = [
(self.x - self.len, self.y - self.len, self.z - self.len),
(self.x + self.len, self.y - self.len, self.z - self.len),
(self.x + self.len, self.y + self.len, self.z - self.len),
(self.x - self.len, self.y + self.len, self.z - self.len),
(self.x - self.len, self.y - self.len, self.z + self.len),
(self.x + self.len, self.y - self.len, self.z + self.len),
(self.x + self.len, self.y + self.len, self.z + self.len),
(self.x - self.len, self.y + self.len, self.z + self.len),
]
def draw(self):
glEnable(GL_DEPTH_TEST)
glEnable(GL_POLYGON_OFFSET_FILL)
glPolygonOffset(1.0, 1.0)
glLineWidth(5)
glColor3fv((0, 0, 0))
glBegin(GL_LINES)
for e in self.edges:
glVertex3fv(self.v[e[0]])
glVertex3fv(self.v[e[1]])
glEnd()
glBegin(GL_QUADS)
for i in range(len(self.surfaces)):
glColor3fv(self.colors[i])
for j in self.surfaces[i]:
glVertex3fv(self.v[j])
glEnd()
答案 0 :(得分:0)
不需要矩阵级联,因为您要做的就是将向量向左或向右旋转90°。
可以通过交换x和y分量来实现(二维)矢量90度旋转。为了向(数学)右旋转,必须将结果的x分量反转。要向左旋转,必须将结果的y分量反转:v = (x, y)
v_right = (-y, x)
v_left = (y, -x)
在函数turn_x()
和turn_y()
中利用它:
def turn_x(layer, direction):
for i in range(len(cube)):
block = cube[i]
if block.x == layer:
block.update(block.x, block.z*direction, -block.y*direction)
block.lr(direction)
def turn_y(layer, direction):
for i in range(len(cube)):
block = cube[i]
if block.y == layer:
block.update(block.z*direction, block.y, -block.x*direction)
block.ud(direction)
如果要使用numpy.matrix
进行相同操作,则必须将2x2矩阵乘以2x1矩阵:
def turn_x(layer, direction):
trans_matrix = np.matrix([[0, 1*direction], [-1*direction, 0]])
for i in range(len(cube)):
block = cube[i]
if block.x == layer:
new_point = trans_matrix * np.matrix([[block.y], [block.z]])
block.update(block.x, new_point.item(0), new_point.item(1))
block.lr(direction)
def turn_y(layer, direction):
trans_matrix = np.matrix([[0, 1*direction], [-1*direction, 0]])
for i in range(len(cube)):
block = cube[i]
if block.y == layer:
new_point = trans_matrix * np.matrix([[block.x], [block.z]])
block.update(new_point.item(0), block.y, new_point.item(1))
block.ud(direction)
此外,您还必须确保函数turn_x()
和方法Piece.lr()
分别turn_y()
和turn_y.ud()
沿相同方向旋转。
如果dir==1
,则.lr()
和.ud()
应该向左旋转。在.lr()
中就是这种情况,但是在.ud()
中是错误的:
def ud(self, dir):
color_ind = []
if dir == -1: # <------------------ == -1 instead of == 1
color_ind = [2, 3, 1, 0, 4, 5]
else:
color_ind = [3, 2, 0, 1, 4, 5]
使用以下主程序。可以使用 << / kbd>,> , ^ 和 v 键旋转场景,以研究旋转。 br />
3 向上旋转左外层,向下旋转 4 。
5 将上一层向右旋转, 6 向左旋转。
def main():
pygame.init()
display = (400, 400)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0] / display[1]), 0.1, 50)
angle_x = 0
angle_y = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_3:
turn_x(1, 1)
if event.key == pygame.K_4:
turn_x(1, -1)
if event.key == pygame.K_5:
turn_y(1, 1)
if event.key == pygame.K_6:
turn_y(1, -1)
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
angle_y += 5
if keys[pygame.K_DOWN]:
angle_y -= 5
if keys[pygame.K_RIGHT]:
angle_x += 5
if keys[pygame.K_LEFT]:
angle_x -= 5
glClearColor(0.6, 0.6, 0.6, 0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0.0, 0.0, -10)
glRotatef(45, 1, 1, 0)
glRotatef(angle_y, -1, 0, 0)
glRotatef(angle_x, 0, 1, 0)
for c in cube:
c.draw()
pygame.display.flip()
pygame.time.wait(10)
main()
无论如何,我建议不要交换立方体的面,也不要更改立方体的顶点。
创建一个最小值为(-1,-1,-1)且最大值为(1、1、1)的多维数据集。
多维数据集的位置由属性(self.x
,self.y
,self.z
)定义,其比例由self.len
定义。
添加一个3x3旋转矩阵属性,该属性定义当前旋转。旋转矩阵由[[1, 0, 0], [0, 1, 0], [0, 0, 1]]
初始化:
class Piece:
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z
self.len = 0.5
self.rotation = np.matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
self.v = [(-1,-1,-1), (1,-1,-1), (1,1,-1), (-1,1,-1), (-1,-1,1), (1,-1,1), (1,1,1), (-1,1,1)]
self.edges = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6),
(6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)]
self.surfaces = [(0, 1, 2, 3), (5, 4, 7, 6), (4, 0, 3, 7), (1, 5, 6, 2),
(4, 5, 1, 0), (3, 2, 6, 7)]
self.colors = [
(0, 0, 1), # blue
(0, 1, 0), # green
(1, 0.5, 0.1), # orange
(1, 0, 0), # red
(1, 1, 0), # yellow
(1, 1, 1)] # white
绘制多维数据集后,请使用glScale
将多维数据集缩放至其大小,然后使用glTranslate
将多维数据集设置为其初始位置。
最终,将缩放和平移的多维数据集旋转到其位置,就好像它是一个“真实”的魔方。为此,必须将3x3矩阵转换为4x4矩阵,并将其乘以glMultMatrix
class Piece:
# [...]
def draw(self):
r = np.array(self.rotation).reshape(9)
rm44 = [r[0],r[1],r[2],0, r[3],r[4],r[5],0, r[6],r[7],r[8],0, 0,0,0,1]
glEnable(GL_DEPTH_TEST)
glEnable(GL_POLYGON_OFFSET_FILL)
glPolygonOffset(1.0, 1.0)
glPushMatrix()
glMultMatrixf(rm44)
glTranslatef(self.x, self.y, self.z)
glScalef(self.len, self.len, self.len)
glLineWidth(5)
glColor3fv((0, 0, 0))
glBegin(GL_LINES)
for e in self.edges:
glVertex3fv(self.v[e[0]])
glVertex3fv(self.v[e[1]])
glEnd()
glBegin(GL_QUADS)
for i in range(len(self.surfaces)):
glColor3fv(self.colors[i])
for j in self.surfaces[i]:
glVertex3fv(self.v[j])
glEnd()
glPopMatrix()
创建3个方法,这些方法可以使多维数据集绕3轴旋转:
class Piece:
# [...]
def rotX(self, dir):
rot_m = np.matrix([[1, 0, 0], [0, 0, dir], [0, -dir, 0]])
self.update(rot_m)
def rotY(self, dir):
rot_m = np.matrix([[0, 0, -dir], [0, 1, 0], [dir, 0, 0]])
self.update(rot_m)
def rotZ(self, dir):
rot_m = np.matrix([[0, dir, 0], [-dir, 0, 0], [0, 0, 1]])
self.update(rot_m)
def update(self, rot_mat):
self.rotation = self.rotation * rot_mat
最后,您需要一个方法,该方法返回多维数据集的当前位置。旋转函数(turn_x
,turn_y
)需要此方法来标识受影响的多维数据集。此方法通过当前旋转(self.x
)旋转立方体的位置矢量(self.y
,self.z
,self.rotation
),并返回结果:
class Piece:
# [...]
def location(self):
current_pos = np.matrix([self.x, self.y, self.z]) * self.rotation
return (current_pos.item(0), current_pos.item(1), current_pos.item(2))
构建多维数据集时,不需要矩阵:
cube = [Piece(x, y, z) for x in range(-1, 2) for y in range(-1, 2) for z in range(-1, 2)]
旋转操作只需要使用direction参数分别调用方法.rotX
,.rotY
.rotZ
。方向必须为1或-1:
def turn_x(layer, direction):
[c.rotX(direction) for c in cube if c.location()[0] == layer]
def turn_y(layer, direction):
[c.rotY(direction) for c in cube if c.location()[1] == layer]
def turn_z(layer, direction):
[c.rotZ(direction) for c in cube if c.location()[2] == layer]