Introduction
This snippet presents a rotating wireframe cube written using pygame. It consists of a set of 3D points, an inlined rotation matrix, and a very simple linear transformation to move the 3D points into 2D space.
One of the curious aspects of this snippet is that due to the way the linear transormation is done, there's no perspective and thus you may see the cube rotating right or rotating left, depending on the way you look at it. Try it!
Result
Code
1 from pygame.locals import *
2 import pygame.draw
3 import pygame.time
4 from math import sin, cos
5
6 ORIGINX = 0
7 ORIGINY = 0
8
9 def draw_3dline(surface, color, a, b):
10 """Convert 3D coordinates to 2D and draw line."""
11 ax, ay = a[0]+(a[2]*0.3)+ORIGINX, a[1]+(a[2]*0.3)+ORIGINY
12 bx, by = b[0]+(b[2]*0.3)+ORIGINX, b[1]+(b[2]*0.3)+ORIGINY
13 pygame.draw.line(surface, color, (ax, ay), (bx, by))
14
15 def draw_cube(surface, color, cube):
16 """Draw 3D cube."""
17 a, b, c, d, e, f, g, h = cube
18 draw_3dline(surface, color, a, b)
19 draw_3dline(surface, color, b, c)
20 draw_3dline(surface, color, c, d)
21 draw_3dline(surface, color, d, a)
22
23 draw_3dline(surface, color, e, f)
24 draw_3dline(surface, color, f, g)
25 draw_3dline(surface, color, g, h)
26 draw_3dline(surface, color, h, e)
27
28 draw_3dline(surface, color, a, e)
29 draw_3dline(surface, color, b, f)
30 draw_3dline(surface, color, c, g)
31 draw_3dline(surface, color, d, h)
32
33 def rotate_3dpoint(p, angle, axis):
34 """Rotate a 3D point around given axis."""
35 ret = [0, 0, 0]
36 cosang = cos(angle)
37 sinang = sin(angle)
38 ret[0] += (cosang+(1-cosang)*axis[0]*axis[0])*p[0]
39 ret[0] += ((1-cosang)*axis[0]*axis[1]-axis[2]*sinang)*p[1]
40 ret[0] += ((1-cosang)*axis[0]*axis[2]+axis[1]*sinang)*p[2]
41 ret[1] += ((1-cosang)*axis[0]*axis[1]+axis[2]*sinang)*p[0]
42 ret[1] += (cosang+(1-cosang)*axis[1]*axis[1])*p[1]
43 ret[1] += ((1-cosang)*axis[1]*axis[2]-axis[0]*sinang)*p[2]
44 ret[2] += ((1-cosang)*axis[0]*axis[2]-axis[1]*sinang)*p[0]
45 ret[2] += ((1-cosang)*axis[1]*axis[2]+axis[0]*sinang)*p[1]
46 ret[2] += (cosang+(1-cosang)*axis[2]*axis[2])*p[2]
47 return ret
48
49 def rotate_object(obj, angle, axis):
50 """Rotate an object around given axis."""
51 for i in range(len(obj)):
52 obj[i] = rotate_3dpoint(obj[i], angle, axis)
53
54 def main():
55 global ORIGINX, ORIGINY
56 pygame.init()
57 screen = pygame.display.set_mode((320,200),
58 HWSURFACE|DOUBLEBUF)
59 # Move origin to center of screen
60 ORIGINX = screen.get_width()/2
61 ORIGINY = screen.get_height()/2
62 cube = [(-50, 50, 50), ( 50, 50, 50),
63 ( 50,-50, 50), (-50,-50, 50),
64 (-50, 50,-50), ( 50, 50,-50),
65 ( 50,-50,-50), (-50,-50,-50)]
66 while True:
67 draw_cube(screen, 255, cube)
68 event = pygame.event.poll()
69 if event.type == QUIT or (event.type == KEYDOWN and
70 event.key == K_ESCAPE):
71 break
72 pygame.display.flip()
73 pygame.time.delay(50)
74 draw_cube(screen, 0, cube)
75 rotate_object(cube, 0.1, (0,1,0))
76 rotate_object(cube, 0.01, (0,0,1))
77 rotate_object(cube, 0.01, (1,0,0))
78
79 if __name__ == "__main__":
80 main()
81
82 # vim:ts=4:sw=4
83
Author
Gustavo Niemeyer <gustavo@niemeyer.net>