def transform_vec3(self, v): """Transforms a vector and returns the result as a Vector3. v -- Vector to transform """ m = self._m x, y, z = v return Vector3.from_floats(x * m[0] + y * m[4] + z * m[8] + m[12], x * m[1] + y * m[5] + z * m[9] + m[13], x * m[2] + y * m[6] + z * m[10] + m[14])
def rotate_vec3(self, v): """Rotates a Vector3 and returns the result. The translation part of the Matrix44 is ignored. v -- Vector to rotate """ m = self._m x, y, z = v return Vector3.from_floats(x * m[0] + y * m[4] + z * m[8], x * m[1] + y * m[5] + z * m[9], x * m[2] + y * m[6] + z * m[10])
def transform_sequence_vec3(self, points): m_0, m_1, m_2, m_3, \ m_4, m_5, m_6, m_7, \ m_8, m_9, m_10, m_11, \ m_12, m_13, m_14, m_15 = self._m return [ Vector3.from_floats(x * m_0 + y * m_4 + z * m_8 + m_12, x * m_1 + y * m_5 + z * m_9 + m_13, x * m_2 + y * m_6 + z * m_10 + m_14) for x, y, z in points ]
def get_row_vec3(self, row_no): """Returns a Vector3 for a given row. row_no -- The row index """ try: r = row_no * 4 x, y, z = self._m[r:r + 3] return Vector3.from_floats(x, y, z) except IndexError: raise IndexError("Row and Column should be 0, 1, 2 or 3")
def create_cube_points(): points = [] # Create a list of points along the edge of a cube for x in range(0, CUBE_SIZE + 1, 20): edge_x = x == 0 or x == CUBE_SIZE for y in range(0, CUBE_SIZE + 1, 20): edge_y = y == 0 or y == CUBE_SIZE for z in range(0, CUBE_SIZE + 1, 20): edge_z = z == 0 or z == CUBE_SIZE if sum((edge_x, edge_y, edge_z)) >= 2: point_x = float(x) - CUBE_SIZE / 2 point_y = float(y) - CUBE_SIZE / 2 point_z = float(z) - CUBE_SIZE / 2 points.append(Vector3(point_x, point_y, point_z)) return points
def iter_transform_vec3(self, points): """Transforms a sequence of points, and yields the result as Vector3s points -- A sequence of vectors """ m_0, m_1, m_2, m_3, \ m_4, m_5, m_6, m_7, \ m_8, m_9, m_10, m_11, \ m_12, m_13, m_14, m_15 = self._m for x, y, z in points: yield Vector3.from_floats(x * m_0 + y * m_4 + z * m_8 + m_12, x * m_1 + y * m_5 + z * m_9 + m_13, x * m_2 + y * m_6 + z * m_10 + m_14)
def get_direction(pressed_keys): direction = Vector3() if pressed_keys[pygame.K_LEFT]: direction.x = -1.0 elif pressed_keys[pygame.K_RIGHT]: direction.x = +1.0 if pressed_keys[pygame.K_UP]: direction.y = +1.0 elif pressed_keys[pygame.K_DOWN]: direction.y = -1.0 if pressed_keys[pygame.K_q]: direction.z = +1.0 elif pressed_keys[pygame.K_a]: direction.z = -1.0 return direction
def render(self): # Set the cube color, applies to all vertices till next call glColor(self.color) # Adjust all the vertices so that the cube is at self.position vertices = [] for v in self.vertices: vertices.append( tuple(Vector3(v) + self.position)) # Draw all 6 faces of the cube glBegin(GL_QUADS) for face_no in range(self.num_faces): glNormal3dv(self.normals[face_no]) v1, v2, v3, v4 = self.vertex_indices[face_no] glVertex(vertices[v1]) glVertex(vertices[v2]) glVertex(vertices[v3]) glVertex(vertices[v4]) glEnd()
def move(self, forward=None, right=None, up=None): """Changes the translation according to a direction vector. To move in opposite directions (i.e back, left and down), first negate the vector. forward -- Units to move in the 'forward' direction right -- Units to move in the 'right' direction up -- Units to move in the 'up' direction """ if forward is not None: self.translate = Vector3(self.translate) + \ Vector3(self.forward) * forward if right is not None: self.translate = Vector3(self.translate) + \ Vector3(self.right) * right if up is not None: self.translate = Vector3(self.translate) + \ Vector3(self.up) * up
def start(): pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.OPENGL|pygame.DOUBLEBUF) resize(*SCREEN_SIZE) init() clock = pygame.time.Clock() # This object renders the 'map' map = Map() # Camera transform matrix cam_matrix = Matrix44() cam_matrix.translate = (10.0, 0.6, 10.0) # Initialize speeds and directions rotation_direction = Vector3() rotation_speed = radians(90.0) movement_direction = Vector3() movement_speed = 5.0 while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: pygame.quit() quit() # Clear the screen, and z-buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) time_passed = clock.tick() time_passed_seconds = time_passed / 1000.0 pressed_keys = pygame.key.get_pressed() # Reset rotation and movement directions rotation_direction.set(0.0, 0.0, 0.0) movement_direction.set(0.0, 0.0, 0.0) # Modify direction vectors for key presses if pressed_keys[pygame.K_LEFT]: rotation_direction.y = +1.0 elif pressed_keys[pygame.K_RIGHT]: rotation_direction.y = -1.0 if pressed_keys[pygame.K_UP]: rotation_direction.x = -1.0 elif pressed_keys[pygame.K_DOWN]: rotation_direction.x = +1.0 if pressed_keys[pygame.K_z]: rotation_direction.z = -1.0 elif pressed_keys[pygame.K_x]: rotation_direction.z = +1.0 if pressed_keys[pygame.K_q]: movement_direction.z = -1.0 elif pressed_keys[pygame.K_a]: movement_direction.z = +1.0 # Calculate rotation matrix and multiply by camera matrix rotation = rotation_direction * rotation_speed * time_passed_seconds rotation_matrix = Matrix44.xyz_rotation(*rotation) cam_matrix *= rotation_matrix # Calcluate movment and add it to camera matrix translate heading = Vector3(cam_matrix.forward) movement = heading * movement_direction.z * movement_speed cam_matrix.translate += movement * time_passed_seconds # Upload the inverse camera matrix to OpenGL glLoadMatrixd(cam_matrix.get_inverse().to_opengl()) # Light must be transformed as well glLight(GL_LIGHT0, GL_POSITION, (0, 1.5, 1, 0)) map.render() pygame.display.flip()
def start(): pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) ball = pygame.image.load("images/ball.png").convert_alpha() points = create_cube_points() fov = 90.0 #degrees viewing_distance = calculate_view_distance(fov, SCREEN_W) points.sort(key=point_z, reverse=True) center_x, center_y = SCREEN_W / 2, SCREEN_H / 2 ball_w, ball_h = ball.get_size() ball_center_x, ball_center_y = ball_w / 2, ball_h / 2 camera_position = Vector3(0.0, 0.0, -700.0) camera_speed = Vector3(300.0, 300.0, 300.0) clock = pygame.time.Clock() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: quit_game() screen.fill(bg_color) pressed_keys = pygame.key.get_pressed() time_passed = clock.tick(30) time_passed_seconds = time_passed / 1000.0 direction = get_direction(pressed_keys) if pressed_keys[pygame.K_w]: fov = min(179.0, fov + 1.0) viewing_distance = calculate_view_distance(fov, SCREEN_W) elif pressed_keys[pygame.K_s]: fov = max(1.0, fov - 1.0) viewing_distance = calculate_view_distance(fov, SCREEN_W) camera_position += direction * camera_speed * time_passed_seconds # Draw the 3D points for point in points: x, y, z = point - camera_position if z > 0: x = x * viewing_distance / z y = -y * viewing_distance / z x += center_x y += center_y screen.blit(ball, (x - ball_center_x, y - ball_center_y)) # Draw the field of view diagram diagram_width = SCREEN_W / 4 diagram_color = (50, 255, 50) diagram_points = [] diagram_points.append((diagram_width / 2, 100 + viewing_distance / 4)) diagram_points.append((0, 100)) diagram_points.append((diagram_width, 100)) diagram_points.append((diagram_width / 2, 100 + viewing_distance / 4)) diagram_points.append((diagram_width / 2, 100)) pygame.draw.lines(screen, diagram_color, False, diagram_points, 2) # Draw the text default_font = pygame.font.get_default_font() font = pygame.font.SysFont(default_font, 24) cam_text = font.render(f"Camera = {str(camera_position)}", True, text_color) screen.blit(cam_text, text_pos) fov_text = font.render(f"Field of view = {int(fov)}", True, text_color) screen.blit(fov_text, fov_text_pos) distance_text = font.render( f"Viewing distance = {round(viewing_distance, 3)}", True, text_color) screen.blit(distance_text, distance_text_pos) pygame.display.flip()
def start(): pygame.init() screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) ball = pygame.image.load("images/ball.png").convert_alpha() fov = 75.0 # degrees viewing_distance = calculate_view_distance(fov, SCREEN_W) points = create_cube_points() points.sort(key=point_z, reverse=True) center_x, center_y = SCREEN_W/2, SCREEN_H/2 ball_w, ball_h = ball.get_size() ball_center_x, ball_center_y = ball_w/2, ball_h/2 cam_position = Vector3(0.0, 0.0, 600.0) rotation = Vector3() rotation_speed = Vector3(math.radians(20), math.radians(20), math.radians(20)) # Labels for the axes font = pygame.font.SysFont(pygame.font.get_default_font(), 16) x_surface = font.render("X", True, white) y_surface = font.render("Y", True, white) z_surface = font.render("Z", True, white) clock = pygame.time.Clock() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: quit_game() screen.fill(bg_color) time_passed = clock.tick(30) time_passed_seconds = time_passed / 1000.0 rotation_direction = Vector3() # Adjust the rotation direction depending on key presses pressed_keys = pygame.key.get_pressed() if pressed_keys[pygame.K_q]: rotation_direction.x = +1.0 elif pressed_keys[pygame.K_a]: rotation_direction.x = -1.0 if pressed_keys[pygame.K_w]: rotation_direction.y = +1.0 elif pressed_keys[pygame.K_s]: rotation_direction.y = -1.0 if pressed_keys[pygame.K_e]: rotation_direction.z = +1.0 elif pressed_keys[pygame.K_d]: rotation_direction.z = -1.0 rotation += rotation_direction * rotation_speed * time_passed_seconds rotation_matrix = Matrix44.x_rotation(rotation.x) rotation_matrix *= Matrix44.y_rotation(rotation.y) rotation_matrix *= Matrix44.z_rotation(rotation.z) transformed_points = [] # Transform all the points and adjust for camera position for point in points: p = rotation_matrix.transform_vec3(point) - cam_position transformed_points.append(p) transformed_points.sort(key=point_z) # Perspective project and blit all the points for x, y, z in transformed_points: if z < 0: x = center_x + x * (-viewing_distance / z) y = center_y + (-y) * (-viewing_distance / z) screen.blit(ball, (x - ball_center_x, y - ball_center_y)) def draw_axis(label, axis, color): axis = rotation_matrix.transform_vec3(axis * 150.0) x, y, z = axis - cam_position x = SCREEN_W/2.0 + x * (-viewing_distance / z) y = SCREEN_H/2.0 + (-y) * (-viewing_distance / z) pygame.draw.line(screen, color, (center_x, center_y), (x, y), 2) w, h = label.get_size() screen.blit(label, (x - w/2, y - h/2)) # Draw the x, y and z axes x_axis = Vector3(1, 0, 0) y_axis = Vector3(0, 1, 0) z_axis = Vector3(0, 0, 1) draw_axis(x_surface, x_axis, red) draw_axis(y_surface, y_axis, green) draw_axis(z_surface, z_axis, blue) # Display rotation information on screen degrees_txt = tuple(math.degrees(r) for r in rotation) rotation_txt = f"Rotation: Q/A {round(degrees_txt[0], 3)}, W/S {round(degrees_txt[1], 3)}, E/D {round(degrees_txt[2], 3)}" txt_surface = font.render(rotation_txt, True, white) screen.blit(txt_surface, (5, 5)) matrix_txt = str(rotation_matrix) txt_y = 25 for line in matrix_txt.split('\n'): txt_surface = font.render(line, True, white) screen.blit(txt_surface, (5, txt_y)) txt_y += 20 pygame.display.flip()
def get_direction(pressed_keys): direction = Vector3() if pressed_keys[pygame.K_LEFT]: direction.x = -1.0 elif pressed_keys[pygame.K_RIGHT]: direction.x = +1.0
def as_vec3(self): """Shorthand for converting to a vector3.""" return Vector3._from_float_sequence(self)
def test(): m = Matrix44.xyz_rotation(radians(45), radians(20), radians(0)) #m.translate += (1, 2, 3) print(m.right) print(m.right.as_vec3()) n = m.copy() r = Matrix44.z_rotation(radians(32)) m *= r print(m) n.fast_mul(r) print(n) print("--Transpose") print(m.get_transpose()) print("--") print(m.get_row(2)) m.transpose() print(m) print() #print (10, 20, 30) + Vector3(1,2,3) m.translate = (m.translate[:3]) + Vector3(10, 20, 30) print(m) print() v = (1., 2., 3.) print(v) vt = m.transform(v) print(vt) vit = m.get_inverse().transform(vt) print(vit) print(m.inverse_transform(vt)) m[1, 2] = 3. print() print(m.x_axis) print(m.translate) m.translate = (1, 2, 3) print(m) identity = Matrix44() #identity.set_row(0, (1, 2, 3, 4)) print(identity) identity[3, 1] = 456 #identity *= Matrix44.scale(20.32, 764.2323, -23) print(identity) print(eval(repr(identity))) print(m) print(m.translate + Vector3(1, 2, 3)) print(m) m.translate = (0, 0, 0)
from gameobjects.vector3d import Vector3 A = (-6, 2, 2) B = (7, 5, 10) plasma_speed = 100 #meters / second AB = Vector3.from_points(A, B) print(f"Vector to droid is {AB}") distance_to_target = AB.get_magnitude() print(f"Distance to droid is {distance_to_target} meters") plasma_heading = AB.get_normalised() print(f"Heading is {plasma_heading}")