Skip to main content
gamedev.net
🔒 Locked 🎯 Unreal

3D in Pygame/Python

Started by Esys 1 reply 2.8k views
Original Post
Esys
Esys
After playing around with some vector graphics in Pygame/Python, I tried throwing together a simple wireframe box and displaying it in 3D, it works great...until I tried adding movement to it. Trying to translate the box 10 pixels to the left or right causes the box to appear to rotate and stretch. I'm guessing it has to do with the camera space or what have you. I'm just applying a translation Matrix to move the box and a Perspective Matrix to display on screen.

import pygame, math
pygame.init()

def rotateY_Matrix(dir):
	rad = math.radians(dir)
	return [
	(math.cos(rad), 0, math.sin(rad), 0),
	(0, 1, 0, 0),
	(-math.sin(rad), 0, math.cos(rad), 0),
	(0, 0, 0, 1)
	]

def origin(faces, center):
	origin = []
	verts = []
	vertList = []
	for face in faces:
		for side in face:
			for i in range(4):
				verts.append(side - center)
			verts = tuple(verts)
			vertList.append(verts)
			verts = []
		vertList = tuple(vertList)
		origin.append(vertList)
		vertList = []
	
	print origin
	return origin
	
def retOrigin(faces, center):
	origin = []
	verts = []
	vertList = []
	for face in faces:
		for side in face:
			for i in range(4):
				verts.append(side + center)
			verts = tuple(verts)
			vertList.append(verts)
			verts = []
		vertList = tuple(vertList)
		origin.append(vertList)
		vertList = []
	
	print origin
	return origin

def perspective_Matrix(): 
	return [
	(1,0,0,0),
	(0,1,0,0),
	(0,0,1,0),
	(0,0,.0036,1)
	]
	
def translateX_Matrix(dx):
	return [
	(1,0,0,dx),
	(0,1,0,0),
	(0,0,1,0),
	(0,0,0,1)
	]

	
def matrixMult(matrix, faces):
	
	n_vect = [] 
	for face in faces:
		n_vect.append(
		(
		(
		(matrix[0][0]*face[0][0] + matrix[0][1]*face[0][1] + matrix[0][2]*face[0][2] + matrix[0][3]*face[0][3]),
		(matrix[1][0]*face[0][0] + matrix[1][1]*face[0][1] + matrix[1][2]*face[0][2] + matrix[1][3]*face[0][3]),
		(matrix[2][0]*face[0][0] + matrix[2][1]*face[0][1] + matrix[2][2]*face[0][2] + matrix[2][3]*face[0][3]),
		(matrix[3][0]*face[0][0] + matrix[3][1]*face[0][1] + matrix[3][2]*face[0][2] + matrix[3][3]*face[0][3])
		),

		(
		(matrix[0][0]*face[1][0] + matrix[0][1]*face[1][1] + matrix[0][2]*face[1][2] + matrix[0][3]*face[1][3]),
		(matrix[1][0]*face[1][0] + matrix[1][1]*face[1][1] + matrix[1][2]*face[1][2] + matrix[1][3]*face[1][3]),
		(matrix[2][0]*face[1][0] + matrix[2][1]*face[1][1] + matrix[2][2]*face[1][2] + matrix[2][3]*face[1][3]),
		(matrix[3][0]*face[1][0] + matrix[3][1]*face[1][1] + matrix[3][2]*face[1][2] + matrix[3][3]*face[1][3])
		),

		(
		(matrix[0][0]*face[2][0] + matrix[0][1]*face[2][1] + matrix[0][2]*face[2][2] + matrix[0][3]*face[2][3]),
		(matrix[1][0]*face[2][0] + matrix[1][1]*face[2][1] + matrix[1][2]*face[2][2] + matrix[1][3]*face[2][3]),
		(matrix[2][0]*face[2][0] + matrix[2][1]*face[2][1] + matrix[2][2]*face[2][2] + matrix[2][3]*face[2][3]),
		(matrix[3][0]*face[2][0] + matrix[3][1]*face[2][1] + matrix[3][2]*face[2][2] + matrix[3][3]*face[2][3])
		),

		(
		(matrix[0][0]*face[3][0] + matrix[0][1]*face[3][1] + matrix[0][2]*face[3][2] + matrix[0][3]*face[3][3]),
		(matrix[1][0]*face[3][0] + matrix[1][1]*face[3][1] + matrix[1][2]*face[3][2] + matrix[1][3]*face[3][3]),
		(matrix[2][0]*face[3][0] + matrix[2][1]*face[3][1] + matrix[2][2]*face[3][2] + matrix[2][3]*face[3][3]),
		(matrix[3][0]*face[3][0] + matrix[3][1]*face[3][1] + matrix[3][2]*face[3][2] + matrix[3][3]*face[3][3])
		)
		)
		)
	return n_vect


def debugPrint(faces):
	face1, face2, face3, face4, face5, face6 = faces
	print "face 1: %s" % face1
	print "face 2: %s" % face2
	print "face 3: %s" % face3
	print "face 4: %s" % face4
	print "face 5: %s" % face5
	print "face 6: %s" % face6

def init():
	face1 = [
	(100,100,0,1), (150,100,0,1), (150,150,0,1), (100,150,0,1)
	]

	face2 = [
	(100,100,50,1), (150,100,50,1), (150,150,50,1), (100,150,50,1)
	]

	face3 = [
	(100,100,0,1), (100,100,50,1), (150,100,50,1), (150,100,0,1)
	]

	face4 = [
	(100,150,0,1), (100,150,50,1), (150,150,50,1), (150,150,0,1)
	]	

	face5 = [
	(100,100,0,1), (100,100,50,1), (100,150,50,1), (100,150,0,1)
	]

	face6 = [
	(100,150,0,1), (150,150,0,1), (150,150,50,1), (100,150,50,1)
	]

	return (face1,face2,face3,face4,face5,face6)
	
def displayPoints(points):
	#f1, f2, f3, f4, f5, f6 = points
	pointList = []
	
	for point in points:
		pointList.append(
		((point[0][0]/point[0][3], point[0][1]/point[0][3]),
		(point[1][0]/point[1][3], point[1][1]/point[1][3]),
		(point[2][0]/point[2][3], point[2][1]/point[2][3]),
		(point[3][0]/point[3][3], point[3][1]/point[3][3])
		))
	
	pointList = tuple(pointList)
	return pointList
	
def drawBox(points, screen):
	for point in points:
		pygame.draw.lines(screen, (255,0,0), True, point, 1)
	
def main():

	clock = pygame.time.Clock()
	running = True

	screen = pygame.display.set_mode((640,480))
	background = pygame.Surface(screen.get_size())
	background.fill((0,0,0)) 
	faces = init()
	points = matrixMult(perspective_Matrix(), faces)
	points = displayPoints(points)
	
	dir = 0
	rotSpeed = 3
	tranSpeed = 10
	center = (0,0,0,0)
	
	while running:
		clock.tick(30)
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				running = False
			elif event.type == pygame.KEYDOWN:
				if event.key == pygame.K_RIGHT:
					print "Right Key"
					faces = matrixMult(translateX_Matrix(tranSpeed), faces)
					points = matrixMult(perspective_Matrix(), faces)
					points = displayPoints(points)
					#debugPrint(faces)
				elif event.key == pygame.K_LEFT:
					print "Left Key"
					faces = matrixMult(translateX_Matrix(-tranSpeed), faces)
					points = matrixMult(perspective_Matrix(), faces)
					points = displayPoints(points)
					#debugPrint(faces)
				elif event.key == pygame.K_e:
					dir += rotSpeed
					if dir > 360:
						dir = rotSpeed
					#faces = origin(faces, center)
					faces = matrixMult(rotateY_Matrix(dir), origin(faces, center))
					#faces = retOrigin(faces, center)
					points = matrixMult(perspective_Matrix(), retOrigin(faces, center))
					points = displayPoints(points)
				elif event.key == pygame.K_q:
					dir -= rotSpeed
					if dir < 0:
						dir = 360 - rotSpeed
					#faces = origin(faces, center)
					faces = matrixMult(rotateY_Matrix(dir), origin(faces, center))
					#faces = retOrigin(faces, center)
					points = matrixMult(perspective_Matrix(), retOrigin(faces, center))
					points = displayPoints(points)
				
		screen.blit(background, (0,0))
		drawBox(points, screen)
		pygame.display.flip()
		
if __name__ == "__main__": main()

EDIT: Cleaned up code [Edited by - Esys on March 23, 2009 7:24:38 PM]
Kylotan
Kylotan
Are you 100% sure all that transform code is correct? There's a whole lot of duplication there which would be better factored out, and it would be easier to see if there are any bugs.

Anyway, my guess is that the (0, 1, 0, 1) line in your rotateY_Matrix matrix should be (0, 1, 0, 0). The '1' values should go down the diagonal and not anywhere else, I believe?
Esys
Esys
I'm actually not using the rotation function as of yet, that's for a later implementation; and yea, I know the transform code is a mess, as it stands it's just a hack job.

As I was thinking of it, it occured to me: I actually might be translating it properly, it's just that my view plane is stationary, so I'm actually viewing the box more and more along the z axis as it comes into view..

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.