├── FUNDING.yml ├── __pycache__ └── event.cpython-39.pyc ├── Tools ├── __pycache__ │ ├── utils.cpython-39.pyc │ ├── Vector.cpython-39.pyc │ ├── camera.cpython-39.pyc │ ├── matrix.cpython-39.pyc │ ├── shapes.cpython-39.pyc │ └── constants.cpython-39.pyc ├── constants.py ├── Objects │ ├── __pycache__ │ │ ├── base.cpython-39.pyc │ │ ├── cube.cpython-39.pyc │ │ └── grid.cpython-39.pyc │ ├── base.py │ ├── grid.py │ └── cube.py ├── matrix.py ├── utils.py ├── camera.py └── Vector.py ├── README.md ├── main.py └── event.py /FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: auctux 2 | ko_fi: auctux 3 | -------------------------------------------------------------------------------- /__pycache__/event.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/__pycache__/event.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/__pycache__/utils.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/__pycache__/utils.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/constants.py: -------------------------------------------------------------------------------- 1 | Width = 1920 2 | Height = 1080 3 | Resolution = (Width, Height) 4 | BackgroundColor = (10, 10,10) 5 | sens= 200 #mouse sensitivity 6 | -------------------------------------------------------------------------------- /Tools/__pycache__/Vector.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/__pycache__/Vector.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/__pycache__/camera.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/__pycache__/camera.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/__pycache__/matrix.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/__pycache__/matrix.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/__pycache__/shapes.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/__pycache__/shapes.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/__pycache__/constants.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/__pycache__/constants.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/Objects/__pycache__/base.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/Objects/__pycache__/base.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/Objects/__pycache__/cube.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/Objects/__pycache__/cube.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/Objects/__pycache__/grid.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Josephbakulikira/Simple-3D-Graphic-pygame/HEAD/Tools/Objects/__pycache__/grid.cpython-39.pyc -------------------------------------------------------------------------------- /Tools/Objects/base.py: -------------------------------------------------------------------------------- 1 | class Object: 2 | def __init__(self, position): 3 | self.position = position 4 | self.transform = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple-3D-Perspective Projection-pygame From Scratch 2 | 3 | ### checkout my youtube channel: https://www.youtube.com/c/Auctux 4 | ### checkout another 3D engine that support lighting and implementation with python : https://github.com/Josephbakulikira/Pygame-3D-engine--Graphic 5 | --- 6 | 7 | it still need a proper Z sorting of faces when moving the cube the occlusion is not finished , still looking for a better way to do that , the faces kinda overlap each other sometimes, 8 | and also apply the zsort to all the shapes in the scene, i might improve this code later,... any help is welcome 9 | 10 | --- 11 | # Inputs(Commands) 12 | " W A S D " to move 13 | " maintain the Right button of the mouse and move the mouse " to rotate the cube 14 | " click and maintain the mouse scroll wheel and move the mouse" to move the camera up and down in scene up and down 15 | " numpad + and numpad -" to zoom in and out 16 | 17 | ![ezgif com-gif-maker (1)](https://user-images.githubusercontent.com/48150537/119762345-2139b280-becb-11eb-986b-4a8efca0b402.gif) 18 | 19 | ![ezgif com-gif-maker](https://user-images.githubusercontent.com/48150537/119512227-c00dc400-bd90-11eb-8643-0298be8bd933.gif) 20 | 21 | 22 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import math 3 | import event 4 | from Tools.matrix import * 5 | from Tools.Objects.cube import Cube 6 | from Tools.Objects.grid import GridPlane 7 | from Tools.Vector import * 8 | from Tools.utils import * 9 | from Tools.constants import * 10 | from Tools.camera import Camera 11 | 12 | 13 | window = pygame.display.set_mode(Resolution) 14 | #hide mouse 15 | pygame.mouse.get_rel() 16 | pygame.mouse.set_visible(False) 17 | a = pygame.event.set_grab(True) 18 | clock = pygame.time.Clock() 19 | fps = 60 20 | 21 | mx, my = 0, 0 22 | m_wheel = { "changed" :False, "value" :0} 23 | 24 | cam = Camera() 25 | angle = 0 26 | 27 | gridPlane = GridPlane(30) 28 | gridPlane.color = (255, 255, 255) 29 | gridPlane.transform = rotationX(-math.pi/2) 30 | c = Cube() 31 | 32 | run = True 33 | while run: 34 | clock.tick(fps) 35 | window.fill(BackgroundColor) 36 | 37 | #pygame.draw.rect(window, (50, 20, 120), pygame.Rect(300, 400, 200, 500)) 38 | 39 | #get events 40 | run = event.GetEvent(mx, my, m_wheel, cam) 41 | cam.HandleInput(m_wheel) 42 | 43 | 44 | gridPlane.Draw(cam, window, False) 45 | c.Draw(cam, window) 46 | 47 | #angle += 0.005 48 | m_wheel["changed"] = False 49 | pygame.display.flip() 50 | pygame.quit() 51 | -------------------------------------------------------------------------------- /Tools/matrix.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def matrix_multiplication(a, b): 4 | columns_a = len(a[0]) 5 | rows_a = len(a) 6 | columns_b = len(b[0]) 7 | rows_b = len(b) 8 | 9 | result_matrix = [[j for j in range(columns_b)] for i in range(rows_a)] 10 | if columns_a == rows_b: 11 | for x in range(rows_a): 12 | for y in range(columns_b): 13 | sum = 0 14 | for k in range(columns_a): 15 | sum += a[x][k] * b[k][y] 16 | result_matrix[x][y] = sum 17 | return result_matrix 18 | 19 | else: 20 | print("columns of the first matrix must be equal to the rows of the second matrix") 21 | return None 22 | 23 | def rotationX(angle): 24 | return [[1, 0, 0], 25 | [0, math.cos(angle), -math.sin(angle)], 26 | [0, math.sin(angle), math.cos(angle)]] 27 | 28 | def rotationY(angle): 29 | return [[math.cos(angle), 0, -math.sin(angle)], 30 | [0, 1, 0], 31 | [math.sin(angle), 0, math.cos(angle)]] 32 | 33 | def rotationZ(angle): 34 | return [[math.cos(angle), -math.sin(angle), 0], 35 | [math.sin(angle), math.cos(angle), 0], 36 | [0, 0 ,1]] 37 | 38 | def projectionMatrix(z): 39 | return [[z, 0, 0], [0, z, 0]] 40 | -------------------------------------------------------------------------------- /event.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from Tools.constants import * 3 | 4 | def GetEvent(mx, my, wheel, camera): 5 | run = True 6 | for event in pygame.event.get(): 7 | if event.type == pygame.QUIT: 8 | run = False 9 | 10 | if event.type == pygame.KEYDOWN: 11 | if event.key == pygame.K_ESCAPE: 12 | run = False 13 | if event.type == pygame.MOUSEMOTION: 14 | if pygame.mouse.get_pressed()[2]: 15 | mx, my = event.rel 16 | mx = mx/sens 17 | my = my/sens 18 | #print(f"{mx}, {my}") 19 | camera.HandleMouseEvent(mx, my) 20 | if pygame.mouse.get_pressed()[1]: 21 | x, y = event.rel 22 | x = x/sens 23 | y = y/sens 24 | camera.HandleMouseEvent2(x, y) 25 | if event.type == pygame.MOUSEBUTTONDOWN: 26 | if event.button == 4: 27 | # mouse wheel input up 28 | wheel["changed"]=True 29 | wheel["value"] = 1 30 | #print("up") 31 | if event.button == 5: 32 | # mouse wheel input down 33 | wheel["changed"]=True 34 | wheel["value"] = -1 35 | #print("Down") 36 | return run 37 | -------------------------------------------------------------------------------- /Tools/utils.py: -------------------------------------------------------------------------------- 1 | import colorsys 2 | from Tools.Vector import * 3 | from math import pow, sqrt 4 | import pygame 5 | 6 | def translate(value, min1, max1, min2, max2): 7 | return min2 + (max2 - min2)* ((value-min1)/(max1-min1)) 8 | 9 | def hsv_to_rgb(h, s, v): 10 | return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h, s, v)) 11 | 12 | def getDistance3D(v1, v2): 13 | return sqrt( pow((v1.x - v2.x), 2) + pow((v1.y - v2.y), 2) + pow((v1.z - v2.z), 2)) 14 | 15 | def getDistance2D(v1, v2): 16 | return sqrt((v2.x - v1.x)*(v2.x - v1.x) + (v2.y -v1.y)*(v2.y - v1.y)) 17 | 18 | def connect_point(i, j, points,window, color, thickness): 19 | a = points[i] 20 | b = points[j] 21 | pygame.draw.line(window, color, (a[0], a[1]), (b[0], b[1]), thickness) 22 | 23 | def DrawLines(window, points, edges, color=(0, 0, 0), thickness=2): 24 | for i, j in edges: 25 | connect_point(i, j, points, window, color, thickness) 26 | 27 | 28 | def DrawPolygons(window, x, y, z, w, points, color): 29 | a = points[x] 30 | b = points[y] 31 | c = points[z] 32 | d = points[w] 33 | polygons= (a[0], a[1]), (b[0], b[1]), (c[0], c[1]), (d[0], d[1]) 34 | pygame.draw.polygon(window, color, polygons) 35 | 36 | def lastIndex(k): 37 | return k[-1] 38 | 39 | def Zsort(faces): 40 | return sorted(faces, key=lastIndex) 41 | 42 | def DrawFaces(window, points, faces, colors, face_list, cam, indices): 43 | o = cam.position.z 44 | face_sort = [] 45 | for face in faces: 46 | front = False 47 | dist = 0 48 | for i in face: 49 | dist += getDistance3D( cam.position, Vector3(indices[i][0], indices[i][1], indices[i][2]) ) 50 | z = dist/4 51 | #print(z) 52 | 53 | face_sort.append([face[0], face[1], face[2], face[3], z]) 54 | face_sort = Zsort(face_sort) 55 | for i, face in enumerate(face_sort): 56 | 57 | DrawPolygons(window, face[0], face[1], face[2], face[3], points, face_list[(face[0], face[1], face[2], face[3])]) 58 | -------------------------------------------------------------------------------- /Tools/camera.py: -------------------------------------------------------------------------------- 1 | from Tools.Vector import Vector3, Vector2 2 | from Tools.matrix import * 3 | import math 4 | import pygame 5 | 6 | def rotationCam(val1, val2): 7 | return [ rotationX(val1), rotationY(val2) ] 8 | 9 | class Camera: 10 | def __init__(self, position=Vector3(0, 1, -12), scale=600, distance=5): 11 | self.position = position 12 | 13 | self.r = Vector2(-0.47507, -0.86499)#camera rotation x and camera rotation y 14 | 15 | self.rotation = rotationCam(self.r.x, self.r.y) 16 | self.scale = scale 17 | self.distance = distance 18 | self.speed = 0.05 19 | self.zoomSpeed = 3 20 | self.transform = 0 21 | 22 | def HandleInput(self, wheel): 23 | keys = pygame.key.get_pressed() 24 | 25 | if keys[pygame.K_UP] : 26 | self.position.y -= self.speed 27 | if keys[pygame.K_DOWN]: 28 | self.position.y += self.speed 29 | if keys[pygame.K_LEFT] or keys[pygame.K_a]: 30 | self.position.x -= self.speed 31 | if keys[pygame.K_RIGHT] or keys[pygame.K_d]: 32 | self.position.x += self.speed 33 | 34 | if keys[pygame.K_q]: 35 | self.rotation -= self.speed 36 | if keys[pygame.K_e]: 37 | self.position.x += self.speed 38 | 39 | if keys[pygame.K_KP_PLUS] or keys[pygame.K_w]: 40 | self.scale += self.zoomSpeed 41 | 42 | if keys[pygame.K_KP_MINUS] or keys[pygame.K_s]: 43 | self.scale -= self.zoomSpeed 44 | 45 | if wheel["changed"] == True: 46 | if (self.position.z + wheel["value"] ) != -4: 47 | self.position.z += wheel["value"] 48 | #print(self.position.z) 49 | 50 | def HandleMouseEvent(self, x, y): 51 | self.r.x += y 52 | self.r.y += x 53 | self.rotation = rotationCam(self.r.x, self.r.y) 54 | #print(self.r) 55 | 56 | def HandleMouseEvent2(self, x, y): 57 | self.position.x += x 58 | self.position.y += y 59 | -------------------------------------------------------------------------------- /Tools/Objects/grid.py: -------------------------------------------------------------------------------- 1 | from Tools.Objects.base import Object 2 | from Tools.matrix import * 3 | from Tools.Vector import * 4 | from Tools.utils import * 5 | from Tools.constants import * 6 | 7 | class GridPlane(Object): 8 | def __init__(self, resolution, cell_size = 400, position=Vector2(Width//2, Height//2)): 9 | super().__init__(position) 10 | self.resolution = resolution 11 | self.color = (140, 140, 140) 12 | self.cell_size = cell_size/50 13 | self.vertices = [] 14 | #generate vertices 15 | for j in range(self.resolution): 16 | for i in range(self.resolution): 17 | x = translate(i, 0, self.resolution, -1, 1) 18 | y = translate(j, 0, self.resolution, -1, 1) 19 | self.vertices.append(Vector3( x * self.cell_size, y * self.cell_size, 1).toMatrix()) 20 | 21 | self.edges = [] 22 | #generate edges 23 | #horizontal connections 24 | for i in range(len(self.vertices)-1): 25 | if i % self.resolution != self.resolution - 1: 26 | self.edges.append( (i, i+1) ) 27 | 28 | #vertical connections 29 | for i in range(len(self.vertices) - self.resolution): 30 | self.edges.append( (i, i+ self.resolution) ) 31 | 32 | def Draw(self, camera, window, ShowPoints=True, ShowLines=True, ShowFaces=False): 33 | points = [] 34 | PointPositions = [] 35 | 36 | for index, vert in enumerate(self.vertices): 37 | transform = matrix_multiplication(self.transform, vert) 38 | #print(transform) 39 | transform = matrix_multiplication(camera.rotation[1], transform) 40 | transform = matrix_multiplication(camera.rotation[0], transform) 41 | 42 | transform[0][0] += camera.position.x 43 | transform[1][0] += camera.position.y 44 | z = 1 / (-camera.position.z - transform[2][0]) 45 | 46 | p = projectionMatrix(z) 47 | t = matrix_multiplication(p, transform) 48 | 49 | x, y = t[0][0], t[1][0] 50 | x = int(x * camera.scale) + self.position.x 51 | y = int(y * camera.scale) + self.position.y 52 | 53 | points.append((x, y, z) ) 54 | PointPositions.append( (transform[0][0], transform[1][0], z) ) 55 | 56 | if ShowFaces == True: 57 | print("draw faces") 58 | #DrawFaces(window, points, self.faces, self.faceColors, self.face_list, camera, PointPositions) 59 | 60 | if ShowLines == True: 61 | DrawLines(window, points, self.edges, self.color) 62 | 63 | if ShowPoints == True: 64 | for x, y, z in points: 65 | pygame.draw.circle(window, (25, 42, 241), (x, y), 5) 66 | -------------------------------------------------------------------------------- /Tools/Objects/cube.py: -------------------------------------------------------------------------------- 1 | from Tools.Objects.base import Object 2 | from Tools.matrix import * 3 | from Tools.Vector import * 4 | from Tools.utils import * 5 | from Tools.constants import * 6 | 7 | class Cube(Object): 8 | def __init__(self, position=Vector2(Width//2, Height//2)): 9 | super().__init__(position) 10 | self.vertices = [ 11 | Vector3( 1, 1, 1).toMatrix(), 12 | Vector3( 1, 1, -1).toMatrix(), 13 | Vector3( 1, -1, 1).toMatrix(), 14 | Vector3( 1, -1, -1).toMatrix(), 15 | Vector3(-1, -1, -1).toMatrix(), 16 | Vector3(-1, 1, -1).toMatrix(), 17 | Vector3(-1, 1, 1).toMatrix(), 18 | Vector3(-1, -1, 1).toMatrix() 19 | ] 20 | self.edges = [(0, 1), (0, 2), (0, 6), 21 | (1, 3), (1, 5), (2, 7), 22 | (2, 3), (4, 7), (4, 3), 23 | (4, 5), (5, 6), (6, 7) 24 | ] 25 | self.faces = [ (0, 1, 3, 2), (2, 3, 4, 7), (0, 1, 5, 6), (0, 2, 7, 6), (6, 7, 4, 5), (1, 3, 4, 5) ] 26 | #front, back 27 | #self.faces = [(0, 2, 7, 6),(1, 3, 4, 5) ] 28 | 29 | #self.faceColors = [(20, 230,10 ), (255,238,173), (255,111,105), (255,204,92), (40,54,85), (75,56,50)] 30 | self.faceColors = [(255, 0,0 ), (0, 255, 0), (0, 0, 255), (255,255,0), (0, 255, 255), (255, 0, 255)] 31 | 32 | self.face_list = dict(zip(self.faces, self.faceColors) ) 33 | 34 | def Draw(self, camera, window, ShowPoints=False, ShowLines=False, ShowFaces=True): 35 | points = [] 36 | PointPositions = [] 37 | for index, vert in enumerate(self.vertices): 38 | transform = matrix_multiplication(self.transform, vert) 39 | transform = matrix_multiplication(camera.rotation[1], transform) 40 | transform = matrix_multiplication(camera.rotation[0], transform) 41 | 42 | transform[0][0] += camera.position.x 43 | transform[1][0] += camera.position.y 44 | z = 1 / (-camera.position.z - transform[2][0]) 45 | 46 | p = projectionMatrix(z) 47 | t = matrix_multiplication(p, transform) 48 | 49 | x, y = t[0][0], t[1][0] 50 | 51 | x = int(x * camera.scale) + self.position.x 52 | y = int(y * camera.scale) + self.position.y 53 | 54 | points.append((x, y, z) ) 55 | PointPositions.append( (transform[0][0], transform[1][0], z) ) 56 | 57 | if ShowFaces == True: 58 | DrawFaces(window, points, self.faces, self.faceColors, self.face_list, camera, PointPositions) 59 | 60 | if ShowLines == True: 61 | DrawLines(window, points, self.edges) 62 | 63 | if ShowPoints == True: 64 | for x, y, z in points: 65 | pygame.draw.circle(window, (25, 42, 241), (x, y), 5) 66 | -------------------------------------------------------------------------------- /Tools/Vector.py: -------------------------------------------------------------------------------- 1 | from math import sqrt, atan2 2 | import pygame 3 | 4 | 5 | class Vector2: 6 | def __init__(self, x=0, y=0): 7 | self.x = x 8 | self.y = y 9 | self.color = (255,255,255) 10 | 11 | def __mul__(a, b): 12 | x,y = 0, 0 13 | if type(b) == Vector2: 14 | x = a.x * b.x 15 | y = a.y * b.y 16 | else: 17 | x = a.x * b 18 | y = a.x * b 19 | return Vector2(x, y) 20 | 21 | def __add__(a, b): 22 | x,y = 0, 0 23 | if type(b) == Vector2: 24 | x = a.x + b.x 25 | y = a.y + b.y 26 | else: 27 | x = a.x + b 28 | y = a.x + b 29 | return Vector2(x, y) 30 | 31 | def __sub__(a, b): 32 | x,y = 0, 0 33 | if type(b) == Vector2: 34 | x = a.x - b.x 35 | y = a.y - b.y 36 | else: 37 | x = a.x - b 38 | y = a.x - b 39 | return Vector2(x, y) 40 | 41 | def __truediv__(a, b): 42 | x,y = 0, 0 43 | if type(b) == Vector2: 44 | x = a.x / b.x 45 | y = a.y / b.y 46 | else: 47 | x = a.x / b 48 | y = a.x / b 49 | return Vector2(x, y) 50 | 51 | def parsetoInt(vec): 52 | return Vector2(int(vec.x), int(vec.y)) 53 | 54 | def getMagnitude(vec): 55 | return sqrt(vec.x * vec.x + vec.y * vec.y) 56 | 57 | def Normalize(vec): 58 | mag = Vector2.getMagnitude(vec) 59 | if mag != 0: 60 | return Vector2(vec.x/mag, vec.y/mag) 61 | return Vector2(1, 1) 62 | 63 | def heading(vec): 64 | angle = atan2(vec.y, vec.x) 65 | #in radians 66 | return angle 67 | 68 | def limit(vec, max_length): 69 | squared_mag = self.magnitude() * self.magnitude() 70 | if squared_mag > (max_length * max_length): 71 | vec.x = vec.x/sqrt(squared_mag) 72 | vec.y = vec.y/sqrt(squared_mag) 73 | vec.x = vec.x * max_length 74 | vec.y = vec.y * max_length 75 | def __repr__(self): 76 | return f'2DVector-> x:{self.x}, y:{self.y}' 77 | 78 | class Vector3: 79 | def __init__(self, x=0, y=0, z=0): 80 | self.x = x 81 | self.y = y 82 | self.z = z 83 | self.color = (255,255,255) 84 | 85 | def __mul__(a, b): 86 | x,y,z = 0, 0, 0 87 | if type(b) == Vector3: 88 | x = a.x * b.x 89 | y = a.y * b.y 90 | z = a.z * b.z 91 | else: 92 | x = a.x * b 93 | y = a.y * b 94 | z = a.z * b 95 | return Vector3(x, y, z) 96 | 97 | def __add__(a, b): 98 | x,y,z = 0, 0, 0 99 | if type(b) == Vector3: 100 | x = a.x + b.x 101 | y = a.y + b.y 102 | z = a.z + b.z 103 | else: 104 | x = a.x + b 105 | y = a.y + b 106 | z = a.z + b 107 | return Vector3(x, y, z) 108 | 109 | def __sub__(a, b): 110 | x,y,z = 0, 0, 0 111 | if type(b) == Vector3: 112 | x = a.x - b.x 113 | y = a.y - b.y 114 | z = a.z - b.z 115 | else: 116 | x = a.x - b 117 | y = a.y - b 118 | z = a.z - b 119 | return Vector3(x, y, z) 120 | 121 | def __truediv__(a, b): 122 | x,y,z = 0, 0, 0 123 | if type(b) == Vector3: 124 | x = a.x / b.x 125 | y = a.y / b.y 126 | z = a.z / b.z 127 | else: 128 | x = a.x / b 129 | y = a.y / b 130 | z = a.z / b 131 | return Vector3(x, y, z) 132 | 133 | def parsetoInt(vec): 134 | return Vector3(int(vec.x), int(vec.y), int(vec.z)) 135 | 136 | def getMagnitude(vec): 137 | return sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) 138 | 139 | def Normalize(vec): 140 | mag = Vector3.getMagnitude(vec) 141 | if mag != 0: 142 | return Vector3(vec.x/mag, vec.y/mag, vec.z/mag) 143 | return Vector3(1, 1, 1) 144 | 145 | def toMatrix(self): 146 | return [[self.x], [self.y], [self.z]] 147 | 148 | # def heading(vec): 149 | # angle = math.atan2(vec.y, vec.x) 150 | # #in radians 151 | # return angle 152 | 153 | def limit(vec, max_length): 154 | squared_mag = self.magnitude() * self.magnitude() 155 | if squared_mag > (max_length * max_length): 156 | vec.x = vec.x/sqrt(squared_mag) 157 | vec.y = vec.y/sqrt(squared_mag) 158 | vec.z = vec.z/sqrt(squared_mag) 159 | vec.x = vec.x * max_length 160 | vec.y = vec.y * max_length 161 | vec.z = vec.z * max_length 162 | def __repr__(self): 163 | return f'3DVector-> x:{self.x}, y:{self.y}, z:{self.z}' 164 | --------------------------------------------------------------------------------