├── FUNDING.yml ├── README.md ├── __pycache__ ├── icosphere.cpython-37.pyc └── matrix.cpython-37.pyc ├── icosphere.py ├── main.py └── matrix.py /FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: auctux 2 | ko_fi: auctux 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3D-perspective-projection-with-python- 2 | 3 | #### please check out my youtube channel : https://www.youtube.com/channel/UCjPk9YDheKst1FlAf_KSpyA 4 | --- 5 | ## here are better versions which support faces and triangles: 6 | #### - https://github.com/Josephbakulikira/Simple-3D-engine-pygame 7 | #### - https://github.com/Josephbakulikira/3D-engine-from-scraph--pygame 8 | -------------------------------------------------------------------------------- /__pycache__/icosphere.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/3D-perspective-projection-with-python-/1d6a7be371a3efc9f77cec8e26100ae46dc3c30f/__pycache__/icosphere.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/matrix.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/3D-perspective-projection-with-python-/1d6a7be371a3efc9f77cec8e26100ae46dc3c30f/__pycache__/matrix.cpython-37.pyc -------------------------------------------------------------------------------- /icosphere.py: -------------------------------------------------------------------------------- 1 | verticies = [ 2 | [ [0.0], [0.0], [-1.0]], 3 | [ [0.7236073017120361], [-0.5257253050804138], [-0.44721952080726624]], 4 | [ [-0.276388019323349], [-0.8506492376327515], [-0.4472198486328125]], 5 | [ [-0.8944262266159058], [0.0], [-0.44721561670303345]], 6 | [ [-0.276388019323349], [0.8506492376327515], [-0.4472198486328125]], 7 | [ [0.7236073017120361], [0.5257253050804138], [-0.44721952080726624]], 8 | [ [0.276388019323349], [-0.8506492376327515], [0.4472198486328125]], 9 | [ [-0.7236073017120361], [-0.5257253050804138], [0.44721952080726624]], 10 | [ [-0.7236073017120361], [0.5257253050804138], [0.44721952080726624]], 11 | [ [0.276388019323349], [0.8506492376327515], [0.4472198486328125]], 12 | [ [0.8944262266159058], [0.0], [0.44721561670303345]], 13 | [ [0.0], [0.0], [1.0]], 14 | [ [-0.16245555877685547], [-0.49999526143074036], [-0.8506544232368469]], 15 | [ [0.42532268166542053], [-0.30901139974594116], [-0.8506541848182678]], 16 | [ [0.26286882162094116], [-0.8090116381645203], [-0.5257376432418823]], 17 | [ [0.8506478667259216], [0.0], [-0.5257359147071838]], 18 | [ [0.42532268166542053], [0.30901139974594116], [-0.8506541848182678]], 19 | [ [-0.525729775428772], [0.0], [-0.8506516814231873]], 20 | [ [-0.6881893873214722], [-0.49999693036079407], [-0.5257362127304077]], 21 | [ [-0.16245555877685547], [0.49999526143074036], [-0.8506544232368469]], 22 | [ [-0.6881893873214722], [0.49999693036079407], [-0.5257362127304077]], 23 | [ [0.26286882162094116], [0.8090116381645203], [-0.5257376432418823]], 24 | [ [0.9510578513145447], [-0.30901262164115906], [0.0]], 25 | [ [0.9510578513145447], [0.30901262164115906], [0.0]], 26 | [ [0.0], [-0.9999999403953552], [0.0]], 27 | [ [0.5877856016159058], [-0.8090167045593262], [0.0]], 28 | [ [-0.9510578513145447], [-0.30901262164115906], [0.0]], 29 | [ [-0.5877856016159058], [-0.8090167045593262], [0.0]], 30 | [ [-0.5877856016159058], [0.8090167045593262], [0.0]], 31 | [ [-0.9510578513145447], [0.30901262164115906], [0.0]], 32 | [ [0.5877856016159058], [0.8090167045593262], [0.0]], 33 | [ [0.0], [0.9999999403953552], [0.0]], 34 | [ [0.6881893873214722], [-0.49999693036079407], [0.5257362127304077]], 35 | [ [-0.26286882162094116], [-0.8090116381645203], [0.5257376432418823]], 36 | [ [-0.8506478667259216], [0.0], [0.5257359147071838]], 37 | [ [-0.26286882162094116], [0.8090116381645203], [0.5257376432418823]], 38 | [ [0.6881893873214722], [0.49999693036079407], [0.5257362127304077]], 39 | [ [0.16245555877685547], [-0.49999526143074036], [0.8506543636322021]], 40 | [ [0.525729775428772], [0.0], [0.8506516814231873]], 41 | [ [-0.42532268166542053], [-0.30901139974594116], [0.8506541848182678]], 42 | [ [-0.42532268166542053], [0.30901139974594116], [0.8506541848182678]], 43 | [ [0.16245555877685547], [0.49999526143074036], [0.8506543636322021]] 44 | ] 45 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import os 3 | import math 4 | from matrix import matrix_multiplication 5 | 6 | os.environ["SDL_VIDEO_CENTERED"]='1' 7 | black, white, blue = (20, 20, 20), (230, 230, 230), (0, 154, 255) 8 | width, height = 1920, 1080 9 | 10 | pygame.init() 11 | pygame.display.set_caption("3D cube Projection") 12 | screen = pygame.display.set_mode((width, height)) 13 | clock = pygame.time.Clock() 14 | fps = 60 15 | 16 | angle = 0 17 | cube_position = [width//2, height//2] 18 | scale = 600 19 | speed = 0.01 20 | points = [n for n in range(8)] 21 | 22 | points[0] = [[-1], [-1], [1]] 23 | points[1] = [[1], [-1], [1]] 24 | points[2] = [[1], [1], [1]] 25 | points[3] = [[-1], [1], [1]] 26 | points[4] = [[-1], [-1], [-1]] 27 | points[5] = [[1], [-1], [-1]] 28 | points[6] = [[1], [1], [-1]] 29 | points[7] = [[-1], [1], [-1]] 30 | 31 | 32 | def connect_point(i, j, k): 33 | a = k[i] 34 | b = k[j] 35 | pygame.draw.line(screen, black, (a[0], a[1]), (b[0], b[1]), 2) 36 | 37 | run = True 38 | while run: 39 | clock.tick(fps) 40 | screen.fill(white) 41 | for event in pygame.event.get(): 42 | if event.type == pygame.QUIT: 43 | run = False 44 | 45 | index = 0 46 | projected_points = [j for j in range(len(points))] 47 | 48 | rotation_x = [[1, 0, 0], 49 | [0, math.cos(angle), -math.sin(angle)], 50 | [0, math.sin(angle), math.cos(angle)]] 51 | 52 | rotation_y = [[math.cos(angle), 0, -math.sin(angle)], 53 | [0, 1, 0], 54 | [math.sin(angle), 0, math.cos(angle)]] 55 | 56 | rotation_z = [[math.cos(angle), -math.sin(angle), 0], 57 | [math.sin(angle), math.cos(angle), 0], 58 | [0, 0 ,1]] 59 | 60 | for point in points: 61 | rotated_2d = matrix_multiplication(rotation_y, point) 62 | rotated_2d = matrix_multiplication(rotation_x, rotated_2d) 63 | rotated_2d = matrix_multiplication(rotation_z, rotated_2d) 64 | distance = 5 65 | z = 1/(distance - rotated_2d[2][0]) 66 | projection_matrix = [[z, 0, 0], 67 | [0, z, 0]] 68 | projected_2d = matrix_multiplication(projection_matrix, rotated_2d) 69 | 70 | x = int(projected_2d[0][0] * scale) + cube_position[0] 71 | y = int(projected_2d[1][0] * scale) + cube_position[1] 72 | projected_points[index] = [x, y] 73 | pygame.draw.circle(screen, blue, (x, y), 10) 74 | index += 1 75 | #draw edges 76 | for m in range(4): 77 | connect_point(m, (m+1)%4, projected_points) 78 | connect_point(m+4, (m+1)%4 + 4, projected_points) 79 | connect_point(m, m+4, projected_points) 80 | 81 | angle += speed 82 | pygame.display.update() 83 | 84 | pygame.quit() 85 | -------------------------------------------------------------------------------- /matrix.py: -------------------------------------------------------------------------------- 1 | 2 | def matrix_multiplication(a, b): 3 | columns_a = len(a[0]) 4 | rows_a = len(a) 5 | columns_b = len(b[0]) 6 | rows_b = len(b) 7 | 8 | result_matrix = [[j for j in range(columns_b)] for i in range(rows_a)] 9 | if columns_a == rows_b: 10 | for x in range(rows_a): 11 | for y in range(columns_b): 12 | sum = 0 13 | for k in range(columns_a): 14 | sum += a[x][k] * b[k][y] 15 | result_matrix[x][y] = sum 16 | return result_matrix 17 | 18 | else: 19 | print("columns of the first matrix must be equal to the rows of the second matrix") 20 | return None 21 | --------------------------------------------------------------------------------