3D Wireframe Cube

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

cube.gif

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>


CategorySnippet

snippets/cube (last edited 2008-03-03 03:34:41 by GustavoNiemeyer)