import math import copy import numpy # todo (once everything is mildly sorted) - find out which of these are unused # functions # converts a coordinate from a coordinate with origin at the middle, to a coordinate with origin at the top left from model import * def conv_coord(points2d, size, scale): for i in range(len(points2d)): points2d[i][0] = (points2d[i][0] * scale) + size[0] / 2 points2d[i][1] = (points2d[i][1] * scale) + size[1] / 2 return points2d # calculates the focal point distance given an FOV and screen size in units def fov_calc(fov, size): fp_distance = (size / (2 * (math.tan(math.radians(fov) / 2)))) return fp_distance # todo use numpy magic to optimise + collapse these # function that returns the angle of a face to the camera def face_angle(points3d, fp_distance, distance): # calculate cross product: vec1 = points3d[0][0], points3d[0][1] - (distance), points3d[0][2] vec2 = cross_product(sub_l(points3d[0], points3d[1]), sub_l(points3d[1], points3d[2])) return math.degrees(_2vec_angle(vec1, vec2)) # returns the cross product of two vectors def cross_product(vector1, vector2): product = [vector1[1]*vector2[2] - vector1[2]*vector2[1], vector1[2]*vector2[0] - vector1[0]*vector2[2], vector1[0]*vector2[1] - vector1[1]*vector2[0]] return product # returns the angle of 2 vectors in radians def _2vec_angle(vector1, vector2): result = math.acos( (vector1[0]*vector2[0] + vector1[1]*vector2[1] + vector1[2]*vector2[2]) / # ----------------------------------------------------------- (math.sqrt((vector1[0] ** 2) + (vector1[1] ** 2) + (vector1[2] ** 2)) * math.sqrt((vector2[0] ** 2) + (vector2[1] ** 2) + (vector2[2] ** 2))) ) return result def sub_l(list1, list2): result = list() for i1, i2 in zip(list1, list2): result.append(i1 - i2) return result # new functions def generate_cam_matrix(rx_d: int, ry_d: int, rz_d: int, player_pos): rx = math.radians(rx_d) ry = math.radians(ry_d) rz = math.radians(rz_d) x_rot = numpy.array([[1, 0, 0, 0], [0, math.cos(rx), math.sin(rx), 0], [0, -math.sin(rx), math.cos(rx), 0], [0, 0, 0, 1]]) y_rot = numpy.array([[math.cos(ry), 0, -math.sin(ry), 0], [0, 1, 0, 0], [math.sin(ry), 0, math.cos(ry), 0], [0, 0, 0, 1]]) z_rot = numpy.array([[math.cos(rz), math.sin(rz), 0, 0], [-math.sin(rz), math.cos(rz), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) rotation_matrix = x_rot.dot(y_rot).dot(z_rot) translation_matrix = numpy.array( [[1, 0, 0, player_pos.x], [0, 1, 0, player_pos.y], [0, 0, 1, player_pos.z], [0, 0, 0, 1]] ) # todo implement mapping matrix # map_matrix = numpy.array([[1, 0, 0 / fp_dis, 0], # [0, 1, 0 / fp_dis, 0], # [0, 0, 1 / fp_dis, 0], # [0, 0, 0, 1]]) return rotation_matrix.dot(translation_matrix) def gen_inv_rot_matrix(rx_d, ry_d, rz_d): rx = math.radians(rx_d) ry = math.radians(- rx_d + 90) rz = math.radians(- rz_d + 90) x_rot = numpy.array([[1, 0, 0, 0], [0, math.cos(rx), math.sin(rx), 0], [0, -math.sin(rx), math.cos(rx), 0], [0, 0, 0, 1]]) y_rot = numpy.array([[math.cos(ry), 0, -math.sin(ry), 0], [0, 1, 0, 0], [math.sin(ry), 0, math.cos(ry), 0], [0, 0, 0, 1]]) z_rot = numpy.array([[math.cos(rz), math.sin(rz), 0, 0], [-math.sin(rz), math.cos(rz), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) return z_rot.dot(y_rot).dot(x_rot) def draw_face(face: Face, cam_matrix: numpy.array, fp_dis): if type(face) is TexturedFace: raise TypeError # has a face to draw and precalculated camera rotation matrix, along with player position as input # the face has the global coordinates here # this function returns the face no matter what (face angle checking must be done elsewhere) _2dPoints: list[Point2D] = [] # apply camera position and rotation for point in face.points: point.apply_matrix(cam_matrix) _2dPoints.append(point.get_2d_point(fp_dis)) return _2dPoints def draw_textured_face(face: Face, transform_matrix: numpy.array): # has face and a camera rotation + position matrix as input, draws the textured face onto the screen return None