Why is there distortion when the cube is on the edge of the screen? - python-3.x

I have made a cube renderer from scratch using pygame.I have been following a guide online and translating it into python and have been pretty successful until I started playing around with the program. Everything works fine, however I noticed that when the cube is further from the center, there is a big distortion effect. Like, unreasonably big distortion. Is there something wrong with how the rays are calculated?
(Arrow keys to move camera)
import pygame
width = 720
height = 480
red = (255, 0, 0)
white = (255, 255, 255)
black = (0,0,0)
screen = pygame.display.set_mode((width, height))
running = True
clock = pygame.time.Clock()
runSpeed = 30
cube = [0, 0, 0], [8, 0, 0], [8, 0, 8], [0, 0, 8], [0, 8, 0], [8, 8, 0], [8, 8, 8], [0, 8, 8]
cubeCoords = [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]
moveCubeCoords = [8, -4, -4]
camCoord = [0, 0, 0]
camSpeed = 1
canvasDis = 1
scale = 80
def coordConvert(x, y):
newX = (width / 2) + x
newY = (height / 2) + y
return newX, newY
def drawCircle(x, y):
pygame.draw.circle(screen, red, (x, y), 5)
def moveCube():
for i in range(len(cube)):
for e in range(3):
cube[i][e] = cube[i][e] + moveCubeCoords[e]
def onEvent(event):
if event.key == pygame.K_UP:
camCoord[1] = camCoord[1] + camSpeed
if event.key == pygame.K_DOWN:
camCoord[1] = camCoord[1] - camSpeed
if event.key == pygame.K_RIGHT:
camCoord[2] = camCoord[2] + camSpeed
if event.key == pygame.K_LEFT:
camCoord[2] = camCoord[2] - camSpeed
print(camCoord)
def main():
pygame.init()
print("Initialized")
pygame.display.set_caption("Cube rendering")
moveCube()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
onEvent(event)
for i, point in enumerate(cube): # gets all coords of cube
pX = point[0] - camCoord[0]
pY = point[1] - camCoord[1]
pZ = point[2] - camCoord[2]
mpX = pZ / pX
mpY = pY / -pX # canvas Y deviation from origin
newCoords = coordConvert(mpX * scale, mpY * scale)
cubeCoords[i][0] = newCoords[0]
cubeCoords[i][1] = newCoords[1]
drawCircle(newCoords[0], newCoords[1])
for i in range(4): # Vert lines
pygame.draw.line(screen, black, (cubeCoords[i][0], cubeCoords[i][1]),
(cubeCoords[i + 4][0], cubeCoords[i + 4][1]), 2)
for i in range(3):# Bottom lines
pygame.draw.line(screen, black, (cubeCoords[i][0], cubeCoords[i][1]),
(cubeCoords[i + 1][0], cubeCoords[i + 1][1]), 2)
pygame.draw.line(screen, black, (cubeCoords[3][0], cubeCoords[3][1]),
(cubeCoords[0][0], cubeCoords[0][1]), 2)
for i in range(3): # Top lines
pygame.draw.line(screen, black, (cubeCoords[i+4][0], cubeCoords[i+4][1]),
(cubeCoords[i + 5][0], cubeCoords[i + 5][1]), 2)
#lazy lines
pygame.draw.line(screen, black, (cubeCoords[3][0], cubeCoords[3][1]),
(cubeCoords[0][0], cubeCoords[0][1]), 2)
pygame.draw.line(screen, black, (cubeCoords[7][0], cubeCoords[7][1]),
(cubeCoords[4][0], cubeCoords[4][1]), 2)
print(cubeCoords)
clock.tick(runSpeed)
pygame.display.update()
screen.fill(white)
if __name__ == '__main__':
main()

The only location that a cubemap IS properly projected is the center of the cube. The images have distortion baked into them and seeing them from any other angle with begin to distort.
If you want to move your player around an area you can make the cube REALLY large to minimize the distortion as the player won't move far from the center relative to the cube. This is typical in game environments.
Here's an explanation of cube map projection.
http://wiki.polycount.com/wiki/Cube_map

What can see is called Perspective distortion.
Anyway you can simplify and cleanup the code:
import pygame
pygame.init()
window = pygame.display.set_mode((600, 400))
width, height = window.get_size()
clock = pygame.time.Clock()
cube = [-1, -1, -1], [1, -1, -1], [1, -1, 1], [-1, -1, 1], [-1, 1, -1], [1, 1, -1], [1, 1, 1], [-1, 1, 1]
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)]
cam_coord, cam_speed = [0, 0, 0], 0.5
scale = 200
translate = [4, 0, 0]
for i in range(len(cube)):
for e in range(3):
cube[i][e] += translate[e]
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
cam_coord[1] -= (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * cam_speed
cam_coord[2] -= (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * cam_speed
cube_coords = []
for point in cube:
x = (width / 2) + scale * (point[2] - cam_coord[2]) / (point[0] - cam_coord[0])
y = (height / 2) + scale * (point[1] - cam_coord[1]) / (point[0] - cam_coord[0])
cube_coords.append((x, y))
window.fill((255, 255, 255))
for edge in edges:
pygame.draw.line(window, (0, 0, 0), cube_coords[edge[0]], cube_coords[edge[1]], 2)
for coord in cube_coords:
pygame.draw.circle(window, (255, 0, 0), coord, 5)
pygame.display.update()
pygame.quit()
exit()

Related

Threads for 4(or more) concurrent array sorts

I create a code that just sorts the same array into 4 windows:
import pygame
pygame.init()
win = pygame.display.set_mode((800, 600))
canvas = pygame.Surface((800, 600))
p1_camera = pygame.Rect(0,0,400,300)
p2_camera = pygame.Rect(400,0,400,300)
p3_camera = pygame.Rect(0,300,400,300)
p4_camera = pygame.Rect(400,300,400,300)
sub1 = canvas.subsurface(p1_camera)
sub2 = canvas.subsurface(p2_camera)
sub3 = canvas.subsurface(p3_camera)
sub4 = canvas.subsurface(p4_camera)
pygame.draw.line(sub2, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub3, (255,255,255), (0,0), (400,0), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (400,0), 10)
pygame.display.set_caption("Bubble sort")
x = 40
y = 40
width = 20
height = [3, 50, 130, 90, 250, 61, 110,
88, 33, 80, 70, 159, 180, 20]
run = True
def show(height):
for i in range(len(height)):
pygame.draw.rect(sub1, (255, 0, 0), (x + 25 * i, y, width, height[i]))
pygame.draw.rect(sub2, (255, 0, 0), (x + 25 * i, y, width, height[i]))
pygame.draw.rect(sub3, (255, 0, 0), (x + 25 * i, y, width, height[i]))
pygame.draw.rect(sub4, (255, 0, 0), (x + 25 * i, y, width, height[i]))
pygame.draw.line(sub2, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub3, (255,255,255), (0,0), (400,0), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (400,0), 10)
win.blit(sub1, (0,0))
win.blit(sub2, (400, 0))
win.blit(sub3, (0, 300))
win.blit(sub4, (400, 300))
while run:
execute = False
pygame.time.delay(10)
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if keys[pygame.K_SPACE]:
execute = True
if execute == False:
win.fill((0, 0, 0))
show(height)
pygame.display.update()
else:
for i in range(len(height) - 1):
for j in range(len(height) - i - 1):
if height[j] > height[j + 1]:
t = height[j]
height[j] = height[j + 1]
height[j + 1] = t
sub1.fill((0, 0, 0))
sub2.fill((0, 0, 0))
sub3.fill((0, 0, 0))
sub4.fill((0, 0, 0))
show(height)
pygame.time.delay(50)
pygame.display.update()
pygame.quit()
It works fine, but my main task was to create parallel sorting threads of different arrays. But I can't imagine how to do it in pygame, because the update goes to the whole window, not just part of it.
I will be grateful for advice or help.
The pygame.display.update() method has an optional argument that allowes you to only update part of the screen. https://www.pygame.org/docs/ref/display.html#pygame.display.update
You can define a rect that will be the only area updated.
You also tagged your question with multi threading, which can be done using this library: https://docs.python.org/3/library/threading.html
This should be everything you need.

How to improve cone - make the bases more like a circle?

I have a code for plotting a cone with some text and arrows like axes. How to change this code to get the bases of the cone looking like circles? Is the problem in the settings of margins? Or is it necessary to define circles in another way?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d
class Arrow3D(FancyArrowPatch):
def __init__(self, xs, ys, zs, *args, **kwargs):
FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
self._verts3d = xs, ys, zs
def draw(self, renderer):
xs3d, ys3d, zs3d = self._verts3d
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
FancyArrowPatch.draw(self, renderer)
nn = 400 # number of points along circle's perimeter
theta = np.linspace(0, 2*np.pi, nn)
rho = np.ones(nn)
# (x,y) represents points on circle's perimeter
x = np.ravel(rho*np.cos(theta))
y = np.ravel(rho*np.sin(theta))
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [5, 5]
figsize = (5, 5)
ax = plt.axes(projection='3d') # set the axes for 3D plot
ax.azim = -88 # y rotation (default=270)
ax.elev = 13 # x rotation (default=0)
# Low, high values of z for plotting 2 circles at different elevation
loz, hiz = -15, 15
# Plot two circles
ax.plot(x, y, hiz)
ax.plot(x, y, loz)
# Set some indices to get proper (x,y) for line plotting
lo1,hi1 = 15, 15+nn//2
lo2,hi2 = lo1+nn//2-27, hi1-nn//2-27
# Plot 3d lines using coordinates of selected points
ax.plot([x[lo1], x[hi1]], [y[lo1], y[hi1]], [loz, hiz])
ax.plot([x[lo2], x[hi2]], [y[lo2], y[hi2]], [loz, hiz])
eps = 0.005
ax.plot([0, 0], [0, 0], [0, 20]) # extend in z direction
ax.plot([0-eps, 0], [0-eps, -5], [0-eps, 0]) # extend in y direction
ax.plot([0, 1.3], [0, 0], [0, 0]) # extend in x direction
ax.plot([0+eps, 0.6], [0+eps, -4], [0+eps, 16]) # v vector
ax.plot([0.63, 0.63], [-4, -4], [16, -0.005]) # vertical projection
ax.plot([0+eps, 0.6], [0+eps, -4], [0+eps, -0.005]) # to the beginning
ax.scatter(0, 0, 20, marker=(3, 0, 0), s=100, clip_on=False)
ax.scatter(0, -5, 0, marker=(3, 0, 43), s=100, clip_on=False)
ax.scatter(1.3, 0, 0, marker=(3, 0, 30), s=100, clip_on=False)
ax.scatter(0.6, -4, 16, marker=(3, 0, 80), s=100, clip_on=False)
ax.scatter(0.6, -4, -0.005, marker=(3, 0, 0), s=100, clip_on=False)
a2 = Arrow3D([0.14, -0.515], [-5.581, 1.358], [14.73, 4.983], mutation_scale=20, arrowstyle="-|>", color="k", connectionstyle="arc3,rad=0.3")
ax.add_artist(a2)
ax.text3D(0.23, -5.23, 23.33, r'$A$')
ax.text3D(1.41, 1.29, -2.7, r'$B$')
ax.text3D(-0.31, 1.46, -12.6, r'$C$')
ax.text3D(0.4, -5.48, 17, r'$D$')
ax.text3D(0.64, 1.57, -9.95, r'$E$')
ax.text3D(-0.2, -5.5, 15.73, r'$F$')
# Hide axes
ax._axis3don = False
# Save the figure (.pdf)
margins = { # vvv margin in inches
"left" : 1 / figsize[0],
"bottom" : -2.45 / figsize[1],
"right" : 1 - 0.5 / figsize[0],
"top" : 1 + 1.8 / figsize[1]
}
fig.subplots_adjust(**margins)
plt.savefig('output.pdf')
plt.show()
From this code I got the following output:
The desired output is bases looking like a circle.
This is the view from above:
It is not a circle but an ellipse.
Desired shape of the cone:

I want to learn how to implement a* path finding in Python3

I found this code online and would really like for someone to explain it simply. I understand most of the initialisation of nodes, but don't understand as much once I get further down. If someone can explain the code near line by line, I would be grateful. The areas I find the most confusing are the calculation sections.
Thanks for any/all responses
class Node():
def __init__(self, parent=None, position=None):
self.parent = parent
self.position = position
self.g = 0
self.h = 0
self.f = 0
def __eq__(self, other):
return self.position == other.position
def astar(maze, start, end):
"""Returns a list of tuples as a path from the given start to the given end in the given maze"""
# Create start and end node
start_node = Node(None, start)
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, end)
end_node.g = end_node.h = end_node.f = 0
# Initialize both open and closed list
open_list = []
closed_list = []
# Add the start node
open_list.append(start_node)
# Loop until you find the end
while len(open_list) > 0:
# Get the current node
current_node = open_list[0]
current_index = 0
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
# Pop current off open list, add to closed list
open_list.pop(current_index)
closed_list.append(current_node)
# Found the goal
if current_node == end_node:
path = []
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
return path[::-1] # Return reversed path
# Generate children
children = []
for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]: # Adjacent squares
# Get node position
node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])
# Make sure within range
if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) -1) or node_position[1] < 0:
continue
# Make sure walkable terrain
if maze[node_position[0]][node_position[1]] != 0:
continue
# Create new node
new_node = Node(current_node, node_position)
# Append
children.append(new_node)
# Loop through children
for child in children:
# Child is on the closed list
for closed_child in closed_list:
if child == closed_child:
continue
# Create the f, g, and h values
child.g = current_node.g + 1
child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2)
child.f = child.g + child.h
# Child is already in the open list
for open_node in open_list:
if child == open_node and child.g > open_node.g:
continue
# Add the child to the open list
open_list.append(child)
def main():
maze = [[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
start = (0, 0)
end = (7, 6)
path = astar(maze, start, end)
print(path)
if __name__ == '__main__':
main()
I suggest you first understand the A* algorithm itself, here is a good video i found, check here. After understanding this, try to code it yourself in whatever language you want and then if you can't understand something ask about that stuff on SO.

How to draw simple 3d axis in python3?

I would like to have names of axes as in the figure.
This could be a good starter. Try experiment with it.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = plt.figure(figsize=[8,8])
ax = fig.gca(projection = '3d')
# some settings
vleng = 4
aleng = vleng/3.
p = np.array([vleng, 0, 0])
q = np.array([0, vleng, 0])
r = np.array([0, 0, vleng])
ax.plot(*np.vstack([[0,0,0], p]).T, color='b')
ax.plot(*np.vstack([[0,0,0], q]).T, color='g')
ax.plot(*np.vstack([[0,0,0], r]).T, color='r')
# plotting arrow at terminal of the lines
ax.quiver(vleng, 0, 0, aleng, 0, 0, \
length=0.5, arrow_length_ratio=0.5, color='r')
ax.quiver(0, vleng, 0, 0, aleng, 0, \
length=0.5, arrow_length_ratio=0.5, color='m')
ax.quiver(0, 0, vleng, 0, 0, aleng, \
length=0.5, arrow_length_ratio=0.5, color='k')
ax.text3D(vleng+1.5, 0, 0, 'X')
ax.text3D(0, vleng+1.0, 0, 'y')
ax.text3D(0, 0, vleng+1.0, 'z')
ax.azim = 35 # y rotation (default=270)
ax.elev = 20 # x rotation (default=0)
ax.dist = 15 # zoom (define perspective)
ax.set_axis_off( ) # hide all grid
ax.set_aspect('equal')
# plot poly1
ax.plot3D( [3.5, 0.25, 2, 3.5], [1, 0.25, 2.5, 1], [1.9, 3.2, 3.8, 1.9], label = 'one line', color='pink' )
# projection of poly1 on xy-plane
ax.plot3D( [3.5, 0.25, 2, 3.5], [1, 0.25, 2.5, 1], [0, 0, 0, 0], label = 'one line', color='gray' )
#ax.legend()
plt.show()

How to correctly add a light to make object get a better view with pygame and pyopengl

I am following the tutorial available in https://pythonprogramming.net/opengl-pyopengl-python-pygame-tutorial/ where he teachs how to render a cube with pyOpenGL an pygame.
When rendering the cube, the tutorial set color to all the vertices of the cubes and then dispays it. However, im my project, i load object from a .obj file using the code provided in https://www.pygame.org/wiki/OBJFileLoader and most of my objects is fully white.
Conclusion: when i render it on screen, i only see full white, which is very ugly. So i tought to use a light to better view the object, but i cannot make this work.
I know very little of pyOpenGl and i cannot find a deeper tutorial of it.
Here is part of the code and the result provided in the tutorial. (vertices, edges, surfaces and color variables are tuple of tuples)
def Cube():
glBegin(GL_QUADS)
for surface in surfaces:
x = 0
for vertex in surface:
x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0,0.0, -5)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glRotatef(1, 3, 1, 1)
Cube()
pygame.display.flip()
pygame.time.wait(10)
main()
i tried to edit the main function to insert a simple light, but the colors in the cube just disapeared:
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(0.0,0.0, -5)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glRotatef(1, 3, 1, 1)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glPushMatrix()
glTranslatef(0.0,0.0, 5)
glLight(GL_LIGHT0, GL_POSITION, (0, 1, 0, 1))
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 1.5, 1, 0))
glPopMatrix()
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
pygame.display.flip()
pygame.time.wait(10)
What i want is the cube with its colors and iluminated by a light. What is wrong with my code and how to fix it?
When lighting (GL_LIGHTING) is enabled, then the color is taken from the material parameters (glMaterial).
If you still want to use the current color, the you have to enable GL_COLOR_MATERIAL
and to set the color material paramters (glColorMaterial).
The ambient light does not depend on the the direction of the light source. You've to define a diffuse and/or specular light. See glLightfv:
When the light position is set by glLightfv(GL_LIGHT0, GL_POSITION, pos), then the position is multiplied by the current model view matrix. So the light position in world space has to be set before the model transformation.
Switch to the matrix mode GL_PROJECTION, before the projection matrix is set. Otherwise the light position would be multiplied by the projection matrix.
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0, 0, -5)
#glLight(GL_LIGHT0, GL_POSITION, (0, 0, 1, 0)) # directional light from the front
glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 1)) # point light from the left, top, front
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))
glEnable(GL_DEPTH_TEST)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE )
glRotatef(1, 3, 1, 1)
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
glDisable(GL_COLOR_MATERIAL)
pygame.display.flip()
The diffuse (and specular) light depends on the Normal vector of the surface.
Define an array of normal vector tuples (x, y, z). Note the following definition is an example. Since you draw a cube, which has 6 faces, you've to define 6 normal vectors, but the direction of the vectors depends on your vertex coordinates, which I do not know.
normals = [
( 0, 0, -1), # surface 0
(-1, 0, 0), # surface 1
( 0, 1, 1), # surface 2
( 1, 0, 0), # surface 3
( 0, 1, 0), # surface 4
( 0, -1, 0) # surface 5
]
And set the proper normal vector when the object is drawn:
def Cube():
glBegin(GL_QUADS)
for i_surface, surface in enumerate(surfaces):
x = 0
glNormal3fv(normals[i_surface]) # set the normal vector the vertices of the surface
for vertex in surface:
x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glColor3fv(colors[0])
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
Enable the Depth Test (glEnable(GL_DEPTH_TEST)) to get an animation like the following:
Full example code:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
( 1, -1, -1), # 0
( 1, 1, -1), # 1
(-1, 1, -1), # 2
(-1, -1, -1), # 3
( 1, -1, 1), # 4
( 1, 1, 1), # 5
(-1, -1, 1), # 6
(-1, 1, 1), # 7
)
surfaces = (
(0,1,2,3),
(3,2,7,6),
(6,7,5,4),
(4,5,1,0),
(1,5,7,2),
(4,0,3,6),
)
normals = [
( 0, 0, -1), # surface 0
(-1, 0, 0), # surface 1
( 0, 0, 1), # surface 2
( 1, 0, 0), # surface 3
( 0, 1, 0), # surface 4
( 0, -1, 0) # surface 5
]
colors = (
(1,1,1),
(0,1,0),
(0,0,1),
(0,1,0),
(0,0,1),
(1,0,1),
(0,1,0),
(1,0,1),
(0,1,0),
(0,0,1),
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7),
)
def Cube():
glBegin(GL_QUADS)
for i_surface, surface in enumerate(surfaces):
x = 0
glNormal3fv(normals[i_surface])
for vertex in surface:
x+=1
glColor3fv(colors[x])
glVertex3fv(verticies[vertex])
glEnd()
glColor3fv(colors[0])
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glVertex3fv(verticies[vertex])
glEnd()
def main():
global surfaces
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
clock = pygame.time.Clock()
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0, 0, -5)
#glLight(GL_LIGHT0, GL_POSITION, (0, 0, 1, 0)) # directional light from the front
glLight(GL_LIGHT0, GL_POSITION, (5, 5, 5, 1)) # point light from the left, top, front
glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 0, 0, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (1, 1, 1, 1))
glEnable(GL_DEPTH_TEST)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE )
glRotatef(1, 3, 1, 1)
Cube()
glDisable(GL_LIGHT0)
glDisable(GL_LIGHTING)
glDisable(GL_COLOR_MATERIAL)
pygame.display.flip()
clock.tick(60)
main()

Resources