# Rotating 3D Cube using Python and Pygame

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.

## 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
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
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
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].z + t[f].z + t[f].z + t[f].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
f = self.faces[face_index]
pointlist = [(t[f].x, t[f].y), (t[f].x, t[f].y),
(t[f].x, t[f].y), (t[f].x, t[f].y),
(t[f].x, t[f].y), (t[f].x, t[f].y),
(t[f].x, t[f].y), (t[f].x, t[f].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.

1. Jessica Stumpp

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.

• lefam

Hello Jessica. Thank you very much.

2. nic

Great, but if you had the work to define a point class, why not a face class too? • lefam

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. 3. George V

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

4. tamer

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.

5. Anastasia

Can i use this for Matplotlib

6. Anastasia

Can i use this for Matplotlib ??

• Elmouden

Yeah i did it with matplotlib and animation

7. bmm

hi,
how can i modify the code to move the cube by external command such as keyboard input – thanks