Beispiel #1
0
    def test_dot_product(self):
        """ Testing * operator for dot_product """
        vec_a = Vec3(1, 2, 3)
        vec_b = Vec3(0, 1, 3)
        dot_product = vec_a * vec_b

        self.assertEqual(11, dot_product, "Asserting dot_product")
Beispiel #2
0
    def test_not_equals(self):
        """ Testing != operator """
        vec_a = Vec3(2, 3, 4)
        vec_b = Vec3(5, 6, 7)

        self.assertFalse(vec_a != vec_a, "Asserting vec_a == vec_a")
        self.assertTrue(vec_a != vec_b, "Asserting vec_a == vec_b")
Beispiel #3
0
    def test_addition(self):
        """ Testing + operator """
        vec_a = Vec3(1, 2, 3)
        vec_b = Vec3(0, 1, 3)
        vec_c = vec_a + vec_b

        self.assertEqual(1, vec_c.x, "Asserting vec3.x")
        self.assertEqual(3, vec_c.y, "Asserting vec3.y")
        self.assertEqual(6, vec_c.z, "Asserting vec3.z")
Beispiel #4
0
    def test_cross_product(self):
        """ Testing // operator """
        vec_a = Vec3(2, 3, 4)
        vec_b = Vec3(5, 6, 7)
        vec_c = vec_a // vec_b

        self.assertEqual(-3, vec_c.x, "Asserting vec3.x")
        self.assertEqual(6, vec_c.y, "Asserting vec3.y")
        self.assertEqual(-3, vec_c.z, "Asserting vec3.z")
Beispiel #5
0
    def test_subtraction(self):
        """ Testing - operator """
        vec_a = Vec3(5, 4, 3)
        vec_b = Vec3(3, 4, 5)
        vec_c = vec_a - vec_b

        self.assertEqual(2, vec_c.x, "Asserting vec3.x")
        self.assertEqual(0, vec_c.y, "Asserting vec3.y")
        self.assertEqual(-2, vec_c.z, "Asserting vec3.z")
Beispiel #6
0
    def test_scalar(self):
        """ Testing * operator for scalar multiplication """
        vec = Vec3(5, 2, 3)
        result = vec * 3

        self.assertEqual(15, result.x, "Asserting vec3.x")
        self.assertEqual(6, result.y, "Asserting vec3.y")
        self.assertEqual(9, result.z, "Asserting vec3.z")

        vec = Vec3(2, 3, 4)
        result = 5 * vec
        self.assertEqual(10, result.x, "Asserting vec3.x")
        self.assertEqual(15, result.y, "Asserting vec3.y")
        self.assertEqual(20, result.z, "Asserting vec3.z")
Beispiel #7
0
    def test_normalize(self):
        """ Testing .normalize() """
        vec = Vec3(4, 3, 0).normalize()

        self.assertEqual(0.8, vec.x, "Asserting vec3.x")
        self.assertEqual(0.6, vec.y, "Asserting vec3.y")
        self.assertEqual(0, vec.z, "Asserting vec3.z")
    def __mul__(self, other: Union[Vec3, Mat4x4]) -> Union[Vec3, Mat4x4]:
        """
        Multiplication of a matrix and vector results in a vector.
        :param other: Vec3 or Mat4x4
        :return: Vec3 or Mat4x4
        """

        if isinstance(other, Vec3):
            x = other.x * self.m[0][0] + other.y * self.m[1][
                0] + other.z * self.m[2][0] + self.m[3][0]
            y = other.x * self.m[0][1] + other.y * self.m[1][
                1] + other.z * self.m[2][1] + self.m[3][1]
            z = other.x * self.m[0][2] + other.y * self.m[1][
                2] + other.z * self.m[2][2] + self.m[3][2]
            w = other.x * self.m[0][3] + other.y * self.m[1][
                3] + other.z * self.m[2][3] + self.m[3][3]

            if w != 0.:
                x /= w
                y /= w
                z /= w

            return Vec3(x, y, z)
        elif isinstance(other, Mat4x4):
            _LOGGER.warning("DEPRECATED METHOD. DON'T USE IT")
            return Mat4x4.multiply_matrix(self, other)
    def __init__(self, *, near: float, far: float, fov: float,
                 screen_height: int, screen_width: int):
        """
        Set up all variables needed for the projection matrix

        :param near: float representing distance to near plane
        :param far: float representing distance to far plane
        :param fov: float representing field-of-view
        :param screen_height: int representing height of the screen
        :param screen_width: int representing width of the screen
        """
        self.near = near,
        self.far = far,
        self.fov = fov,
        self.screen_height = screen_height
        self.screen_width = screen_width
        self.aspect_ration = float(screen_height / screen_width)
        self.fov_rad = 1.0 / tan(fov * 0.5 / 180.0 * pi)
        self.theta = pi / 4
        self.time_diff = 1

        self.camera = Camera(Vec3(0, 0, -10))
        self.projection_matrix = self._make_projection_matrix(far, near)

        # Get objects for the scene
        self.objects = get_objects_for_scene()
Beispiel #10
0
    def read_obj_model(path: str) -> [Triangle]:
        """
        Read .obj file and return a list of Triangles, a Model.

        :param path: Path to the .obj file
        :return: Model represented as a list of Triangle objects
        """
        v = []  # Vertices
        f = []  # Faces/Triangles

        with open(path) as file:
            lines = file.readlines()

        for line in lines:
            line = line.split()  # Remove whitespaces

            # Based of first char put in appropriate container
            if 'v' in line:
                v.append(Vec3(float(line[1]), float(line[2]), float(line[3])))
            elif 'f' in line:
                f.append(
                    Triangle(v[int(line[1]) - 1], v[int(line[2]) - 1],
                             v[int(line[3]) - 1]))
            else:
                continue

        return f
    def test_vector_multiplication_with_vec3(self):
        """ Testing * operator with Vec3 """
        vec = Vec3(1, 2, 3)
        matrix = Mat4x4()

        matrix.m[0] = [4, 3, 1, 0]
        matrix.m[2] = [2, 2, 2, 0]

        result = matrix * vec

        self.assertEqual(10, result.x,
                         "Asserting vec.x from matrix-vector multiplication")
        self.assertEqual(9, result.y,
                         "Asserting vec.y from matrix-vector multiplication")
        self.assertEqual(7, result.z,
                         "Asserting vec.z from matrix-vector multiplication")
    def render_frame(self, window: Canvas, time_diff: float) -> Canvas:
        # Clear screen
        window.delete("all")

        # update time_diff
        self.time_diff = time_diff

        # update camera position
        self.update_camera_position()

        # Get objects in scene
        objects = copy.deepcopy(self.objects)

        # Angle for rotation
        # self.theta += time_diff * 1.0

        # Setup Z and X rotation matrices
        z_rotate = Mat4x4.z_rotation_matrix(3 * pi)
        x_rotate = Mat4x4.x_rotation_matrix(2 * pi)

        # Setup Translation matrix
        translation_matrix = Mat4x4.translation_matrix(0.0, 0.0, 0.0)

        # Setup World matrix
        world_matrix = Mat4x4.multiply_matrix(z_rotate, x_rotate)
        world_matrix = Mat4x4.multiply_matrix(world_matrix, translation_matrix)

        # Make point_at matrix
        up_vector = Vec3(0, 1, 0)
        target_vector = Vec3(0, 0, 1)
        camera_rotation = Mat4x4.y_rotation_matrix(self.camera.yaw)
        self.camera.look_direction = camera_rotation * target_vector
        target_vector = self.camera.position + self.camera.look_direction

        camera_matrix = self._point_at_matrix(self.camera.position,
                                              target_vector, up_vector)
        camera_view = self._quick_inverse_matrix(camera_matrix)

        # Triangle to be drawn
        triangles_to_draw = []

        # Loop on objects in scene
        for obj in objects:
            # Loop on triangles in an object
            for tri in obj:

                # Perform Translate-Rotate-Scale matrix multiplication on triangle
                tri_transformed = tri
                tri_transformed.p[0] = world_matrix * tri.p[0]
                tri_transformed.p[1] = world_matrix * tri.p[1]
                tri_transformed.p[2] = world_matrix * tri.p[2]

                # Get normal of triangle
                line_a = tri_transformed.p[1] - tri_transformed.p[0]
                line_b = tri_transformed.p[2] - tri_transformed.p[0]
                normal = line_a // line_b
                normal.normalize()

                if normal * (tri_transformed.p[0] -
                             self.camera.position) < 0.0:
                    # Illuminate triangle
                    light_direction = Vec3(
                        0.0, 0.0, -1.0).normalize()  # towards the camera
                    dot_product = max(0.1, light_direction * normal)
                    tri_transformed.angle_to_light = dot_product

                    # Convert World Space into View Space
                    tri_viewed = tri_transformed
                    tri_viewed.p[0] = camera_view * tri_transformed.p[0]
                    tri_viewed.p[1] = camera_view * tri_transformed.p[1]
                    tri_viewed.p[2] = camera_view * tri_transformed.p[2]

                    # Project triangles
                    tri_projected = self._project_triangle(tri_viewed)

                    # Scale triangle into view
                    tri_scaled = self._scale_triangle(tri_projected)

                    # Store triangle
                    triangles_to_draw.append(tri_scaled)

        # Sort the triangles using *z-buffer*
        triangles_to_draw.sort(key=lambda x:
                               (x.p[0].z + x.p[1].z + x.p[2].z) / 3.0,
                               reverse=True)

        # Draw triangles to screen
        for triangle in triangles_to_draw:
            self._draw_triangle(triangle, window)

        # Add debug info to window
        camera_text = (f"Camera:\n"
                       f" X: {self.camera.position.x}\n"
                       f" Y: {self.camera.position.y}\n"
                       f" Z: {self.camera.position.z}\n"
                       f" Yaw: {self.camera.yaw}")

        triangle_count = 0
        for obj in objects:
            triangle_count = triangle_count + len(obj)

        triangle_text = ("Triangles:\n"
                         f" Total: {triangle_count}\n"
                         f" Drawn: {len(triangles_to_draw)}")

        window.create_text(5, 5, anchor=NW, text=camera_text, fill="red")
        window.create_text(5, 100, anchor=NW, text=triangle_text, fill="red")

        return window
 def __init__(self, position: Vec3):
     self.position = position
     self.origin = copy.deepcopy(self.position)
     self.look_direction = Vec3(0, 0, 1)
     self.yaw = 0
     self.move_direction = None