From b318076f05dc824b9b136b0535cf69e5ad1c6abe Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Tue, 14 Jul 2020 00:56:25 -0500 Subject: [PATCH] Cleaned up the proof of concept code to be more object oriented. Functionally, some mouse and key bindings were added to make the demo a bit more interactive. --- main.py | 167 +++++++++++++++++++++++++++++------------------------ matrix.py | 47 +++++++++++++++ vectors.py | 17 ++++++ 3 files changed, 156 insertions(+), 75 deletions(-) create mode 100644 matrix.py create mode 100644 vectors.py diff --git a/main.py b/main.py index 04ceffa..4b8f431 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ import window import math import copy +from matrix import Matrix4x4, Matrix3x3 +from vectors import Vector4d, Vector3d, Vector2d ui = window.Window(600, 600) near_plane = 0.1 @@ -33,97 +35,112 @@ tris = [ [[ 1.0, 0.0, 1.0], [0.0, 0.0, 0.0], [1.0, 0.0, 0.0 ]] ] -def matric_mul(d_vector, transform_mat): - out_matrix = [] - out_matrix.append(d_vector[0] * transform_mat[0][0] + d_vector[1] * transform_mat[1][0] + d_vector[2] * transform_mat[2][0] + transform_mat[3][0]) # x - out_matrix.append(d_vector[0] * transform_mat[0][1] + d_vector[1] * transform_mat[1][1] + d_vector[2] * transform_mat[2][1] + transform_mat[3][1]) # y - out_matrix.append(d_vector[0] * transform_mat[0][2] + d_vector[1] * transform_mat[1][2] + d_vector[2] * transform_mat[2][2] + transform_mat[3][2]) # z - # 4th row - w = d_vector[0] * transform_mat[0][3] + d_vector[1] * transform_mat[1][3] + d_vector[2] * transform_mat[2][3] + transform_mat[3][3] - - if w != 0: - out_matrix[0] /= w - out_matrix[1] /= w - out_matrix[2] /= w - - return out_matrix - -def make_matrix(row1, row2, row3, row4): - mat = [] - mat.append([]) - mat[0].append([row1[0], row1[1], row1[2], row1[3]]) - mat.append([]) - mat[1].append([row2[0], row2[1], row2[2], row2[3]]) - mat.append([]) - mat[2].append([row3[0], row3[1], row3[2], row3[3]]) - mat.append([]) - mat[3].append([row4[0], row4[1], row4[2], row4[3]]) - - return mat - def main(): + ui.thetax = 1 + ui.window.bind('', left) + ui.window.bind('', right) + ui.window.bind('', mouse_start) + ui.window.bind('', mouse_end) + ui.canvas.old_coords = None ui.window.after(0, draw_scene) ui.show() +def left(event): + ui.theta -= .01 + +def right(event): + ui.theta += .01 + +def mouse_start(event): + #x, y = + ui.canvas.old_coords = event.x, event.y #x, y + +def mouse_end(event): + x, y = ui.canvas.old_coords[0] - event.x, ui.canvas.old_coords[1] - event.y + if x < 0: + ui.theta += .01 + else: + ui.theta -= .01 + + print(ui.theta) + + if y < 0: + ui.thetax += .01 + else: + ui.thetax -= .01 + #ui.theta += x / ui.width def draw_scene(): ui.canvas.delete("all") - ui.theta += .01 - projection_matrix = [] - rotation_matrix_z = [] - rotation_matrix_x = [] + #ui.theta += .01 # scaling factor aspect_ratio = ui.height / ui.width fov_rad = ui.theta / math.tan(fov * 0.5 / 180.0 * math.pi) - projection_matrix.append([aspect_ratio * fov_rad, 0, 0, 0]) - projection_matrix.append([0, fov_rad, 0, 0]) - projection_matrix.append([0, 0, far_plane / (far_plane - near_plane), 1.0]) - projection_matrix.append([0, 0, -far_plane * near_plane / (far_plane - near_plane), 0]) + row0 = Vector4d(aspect_ratio * fov_rad, 0, 0, 0) + row1 = Vector4d(0, fov_rad, 0, 0) + row2 = Vector4d(0, 0, far_plane / (far_plane - near_plane), 1.0) + row3 = Vector4d(0, 0, -far_plane * near_plane / (far_plane - near_plane), 0) - rotation_matrix_z.append([math.cos(ui.theta), math.sin(ui.theta), 0, 0]) - rotation_matrix_z.append([-math.sin(ui.theta), math.cos(ui.theta), 0, 0]) - rotation_matrix_z.append([0, 0, 1, 0]) - rotation_matrix_z.append([0, 0, 0, 1]) - #-------------------------------------------- - rotation_matrix_x.append([1, 0, 0, 0]) - rotation_matrix_x.append([0, math.cos(ui.theta * 0.5), math.sin(ui.theta * 0.5), 0]) - rotation_matrix_x.append([0, -math.sin(ui.theta * 0.5), math.cos(ui.theta * 0.5), 0]) - rotation_matrix_x.append([0, 0, 0, 1]) - - for tri in tris: - rotated_z = [] - rotated_z.append(matric_mul(tri[0], rotation_matrix_z)) - rotated_z.append(matric_mul(tri[1], rotation_matrix_z)) - rotated_z.append(matric_mul(tri[2], rotation_matrix_z)) + projection_matrix = Matrix4x4(row0, row1, row2, row3) + + row0 = Vector4d(math.cos(ui.theta), math.sin(ui.theta), 0, 0) + row1 = Vector4d(-math.sin(ui.theta), math.cos(ui.theta), 0, 0) + row2 = Vector4d(0, 0, 1, 0) + row3 = Vector4d(0, 0, 0, 1) + + rotation_matrix_z = Matrix4x4(row0, row1, row2, row3) + + row0 = Vector4d(1, 0, 0, 0) + row1 = Vector4d(0, math.cos(ui.thetax * 0.5), math.sin(ui.thetax * 0.5), 0) + row2 = Vector4d(0, -math.sin(ui.thetax * 0.5), math.cos(ui.thetax * 0.5), 0) + row3 = Vector4d(0, 0, 0, 1) + + rotation_matrix_x = Matrix4x4(row0, row1, row2, row3) + + for t in tris: + row0 = Vector3d(t[0][0], t[0][1], t[0][2]) + row1 = Vector3d(t[1][0], t[1][1], t[1][2]) + row2 = Vector3d(t[2][0], t[2][1], t[2][2]) - rotated_x = [] - rotated_x.append(matric_mul(rotated_z[0], rotation_matrix_x)) - rotated_x.append(matric_mul(rotated_z[1], rotation_matrix_x)) - rotated_x.append(matric_mul(rotated_z[2], rotation_matrix_x)) + tri = Matrix3x3(row0, row1, row2) + + row0 = rotation_matrix_z.multiply_3d(tri.row0) + row1 = rotation_matrix_z.multiply_3d(tri.row1) + row2 = rotation_matrix_z.multiply_3d(tri.row2) + + rotated_z = Matrix3x3(row0, row1, row2) + + row0 = rotation_matrix_x.multiply_3d(rotated_z.row0) + row1 = rotation_matrix_x.multiply_3d(rotated_z.row1) + row2 = rotation_matrix_x.multiply_3d(rotated_z.row2) + + rotated_x = Matrix3x3(row0, row1, row2) translated = copy.copy(rotated_x) - translated[0][2] = rotated_x[0][2] + 3.0 - translated[1][2] = rotated_x[1][2] + 3.0 - translated[2][2] = rotated_x[2][2] + 3.0 + translated.row0.z += 3.0 + translated.row1.z += 3.0 + translated.row2.z += 3.0 - projected = [] - projected.append(matric_mul(translated[0], projection_matrix)) - projected.append(matric_mul(translated[1], projection_matrix)) - projected.append(matric_mul(translated[2], projection_matrix)) + row0 = projection_matrix.multiply_3d(translated.row0) + row1 = projection_matrix.multiply_3d(translated.row1) + row2 = projection_matrix.multiply_3d(translated.row2) - projected[0][0] += 1 - projected[0][1] += 1 - projected[1][0] += 1 - projected[1][1] += 1 - projected[2][0] += 1 - projected[2][1] += 1 - projected[0][0] *= .5 * ui.width - projected[0][1] *= .5 * ui.height - projected[1][0] *= .5 * ui.width - projected[1][1] *= .5 * ui.height - projected[2][0] *= .5 * ui.width - projected[2][1] *= .5 * ui.height - coords = [projected[0][0], projected[0][1], projected[1][0], projected[1][1], projected[2][0], projected[2][1]] + projected = Matrix3x3(row0, row1, row2) + + projected.row0.x += 1 + projected.row0.y += 1 + projected.row1.x += 1 + projected.row1.y += 1 + projected.row2.x += 1 + projected.row2.y += 1 + projected.row0.x *= .5 * ui.width + projected.row0.y *= .5 * ui.height + projected.row1.x *= .5 * ui.width + projected.row1.y *= .5 * ui.height + projected.row2.x *= .5 * ui.width + projected.row2.y *= .5 * ui.height + + coords = [projected.row0.x, projected.row0.y, projected.row1.x, projected.row1.y, projected.row2.x, projected.row2.y] ui.canvas.create_polygon(coords, fill="", outline="black") ui.canvas.update() diff --git a/matrix.py b/matrix.py new file mode 100644 index 0000000..2d07717 --- /dev/null +++ b/matrix.py @@ -0,0 +1,47 @@ +import vectors + +class Matrix4x4: + def __init__(self): + self.row0 = None + self.row1 = None + self.row2 = None + self.row3 = None + + def __init__(self, row0, row1, row2, row3): + if not isinstance(row0, vectors.Vector4d): + raise ValueError("Row must be a Vector4d object.", row0) + if not isinstance(row1, vectors.Vector4d): + raise ValueError("Row must be a Vector4d object.", row1) + if not isinstance(row2, vectors.Vector4d): + raise ValueError("Row must be a Vector4d object.", row2) + if not isinstance(row3, vectors.Vector4d): + raise ValueError("Row must be a Vector4d object.", row3) + + self.row0 = row0 + self.row1 = row1 + self.row2 = row2 + self.row3 = row3 + + def multiply_3d(self, vector3d): + x = vector3d.x * self.row0.x + vector3d.y * self.row1.x + vector3d.z * self.row2.x + self.row3.x + y = vector3d.x * self.row0.y + vector3d.y * self.row1.y + vector3d.z * self.row2.y + self.row3.y + z = vector3d.x * self.row0.z + vector3d.y * self.row1.z + vector3d.z * self.row2.z + self.row3.z + w = vector3d.x * self.row0.w + vector3d.y * self.row1.w + vector3d.z * self.row2.w + self.row3.w + + if w != 0: + x /= w + y /= w + z /= w + + return vectors.Vector3d(x, y, z) + +class Matrix3x3: + def __init__(self): + self.row0 = None + self.row1 = None + self.row2 = None + + def __init__(self, row0, row1, row2): + self.row0 = row0 + self.row1 = row1 + self.row2 = row2 diff --git a/vectors.py b/vectors.py new file mode 100644 index 0000000..7fdeba6 --- /dev/null +++ b/vectors.py @@ -0,0 +1,17 @@ +class Vector4d: + def __init__(self, x, y, z, w): + self.x = x + self.y = y + self.z = z + self.w = w + +class Vector3d: + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + +class Vector2d: + def __init__(self, x, y): + self.x = x + self.y = y