In one of my previous tutorials, I have shown how to make a simulation of a wireframe cube using Python and Pygame. Today, we will make a few modifications in the code from that tutorial to make an awesome rotating solid cube. See below the video of the rotating cube.
NOTE: If you want to stay updated, consider following me on twitter at http://twitter.com/codentronix.
Click here to download the source code.
The Code
""" Simulation of a rotating 3D Cube Developed by Leonel Machava <[email protected]> http://codeNtronix.com """ import sys, math, pygame from operator import itemgetter class Point3D: def __init__(self, x = 0, y = 0, z = 0): self.x, self.y, self.z = float(x), float(y), float(z) def rotateX(self, angle): """ Rotates the point around the X axis by the given angle in degrees. """ rad = angle * math.pi / 180 cosa = math.cos(rad) sina = math.sin(rad) y = self.y * cosa - self.z * sina z = self.y * sina + self.z * cosa return Point3D(self.x, y, z) def rotateY(self, angle): """ Rotates the point around the Y axis by the given angle in degrees. """ rad = angle * math.pi / 180 cosa = math.cos(rad) sina = math.sin(rad) z = self.z * cosa - self.x * sina x = self.z * sina + self.x * cosa return Point3D(x, self.y, z) def rotateZ(self, angle): """ Rotates the point around the Z axis by the given angle in degrees. """ rad = angle * math.pi / 180 cosa = math.cos(rad) sina = math.sin(rad) x = self.x * cosa - self.y * sina y = self.x * sina + self.y * cosa return Point3D(x, y, self.z) def project(self, win_width, win_height, fov, viewer_distance): """ Transforms this 3D point to 2D using a perspective projection. """ factor = fov / (viewer_distance + self.z) x = self.x * factor + win_width / 2 y = -self.y * factor + win_height / 2 return Point3D(x, y, self.z) class Simulation: def __init__(self, win_width = 640, win_height = 480): pygame.init() self.screen = pygame.display.set_mode((win_width, win_height)) pygame.display.set_caption("Simulation of a rotating 3D Cube (http://codeNtronix.com)") self.clock = pygame.time.Clock() self.vertices = [ Point3D(-1,1,-1), Point3D(1,1,-1), Point3D(1,-1,-1), Point3D(-1,-1,-1), Point3D(-1,1,1), Point3D(1,1,1), Point3D(1,-1,1), Point3D(-1,-1,1) ] # Define the vertices that compose each of the 6 faces. These numbers are # indices to the vertices list defined above. self.faces = [(0,1,2,3),(1,5,6,2),(5,4,7,6),(4,0,3,7),(0,4,5,1),(3,2,6,7)] # Define colors for each face self.colors = [(255,0,255),(255,0,0),(0,255,0),(0,0,255),(0,255,255),(255,255,0)] self.angle = 0 def run(self): """ Main Loop """ while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() self.clock.tick(50) self.screen.fill((0,32,0)) # It will hold transformed vertices. t = [] for v in self.vertices: # Rotate the point around X axis, then around Y axis, and finally around Z axis. r = v.rotateX(self.angle).rotateY(self.angle).rotateZ(self.angle) # Transform the point from 3D to 2D p = r.project(self.screen.get_width(), self.screen.get_height(), 256, 4) # Put the point in the list of transformed vertices t.append(p) # Calculate the average Z values of each face. avg_z = [] i = 0 for f in self.faces: z = (t[f[0]].z + t[f[1]].z + t[f[2]].z + t[f[3]].z) / 4.0 avg_z.append([i,z]) i = i + 1 # Draw the faces using the Painter's algorithm: # Distant faces are drawn before the closer ones. for tmp in sorted(avg_z,key=itemgetter(1),reverse=True): face_index = tmp[0] f = self.faces[face_index] pointlist = [(t[f[0]].x, t[f[0]].y), (t[f[1]].x, t[f[1]].y), (t[f[1]].x, t[f[1]].y), (t[f[2]].x, t[f[2]].y), (t[f[2]].x, t[f[2]].y), (t[f[3]].x, t[f[3]].y), (t[f[3]].x, t[f[3]].y), (t[f[0]].x, t[f[0]].y)] pygame.draw.polygon(self.screen,self.colors[face_index],pointlist) self.angle += 1 pygame.display.flip() if __name__ == "__main__": Simulation().run()
If you liked this experiment, please consider leaving a comment, or sharing this post using one of the buttons below, or subscribing to the blog.
Hi there, I found your site via Google at the same time as searching for a similar matter, your web site got here up, it seems to be great. I have bookmarked it in my google bookmarks.
Hello Jessica. Thank you very much.
Great, but if you had the work to define a point class, why not a face class too?
Hello Nic. Undoubtedly, a face class would contribute to a good (OO) design and a more elegant code. However, my intention was to keep it as simple as possible. As you can see the simulation was made using very few lines of code.
I will leave the improvement of the code as an exercise for my readers.
hello!very nice work!i found samples of your work from google and i was wondering if you can help me with a project i am preparing.i want to connect a basic atom pro 28 via usb to blender and i want to be able to control the rotation of an object with a potentiometer.can you plz guide me because i am new in the programming
Hi
I learn some pascal in graphics, then it was on VAX systems, now I am trying to go back to programming and use python and C++
I think you are making good graphics.
thanks for sharing it with us.