Ejemplo n.º 1
0
    def testTransformation(self):
        sphere = Sphere(transformation=translation(Vec(10.0, 0.0, 0.0)))

        ray1 = Ray(origin=Point(10, 0, 2), dir=-VEC_Z)
        intersection1 = sphere.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(10.0, 0.0, 1.0),
            normal=Normal(0.0, 0.0, 1.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=sphere.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(13, 0, 0), dir=-VEC_X)
        intersection2 = sphere.ray_intersection(ray2)
        assert intersection2
        assert HitRecord(
            world_point=Point(11.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=2.0,
            ray=ray2,
            material=sphere.material,
        ).is_close(intersection2)

        # Check if the sphere failed to move by trying to hit the untransformed shape
        assert not sphere.ray_intersection(
            Ray(origin=Point(0, 0, 2), dir=-VEC_Z))

        # Check if the *inverse* transformation was wrongly applied
        assert not sphere.ray_intersection(
            Ray(origin=Point(-10, 0, 0), dir=-VEC_Z))
Ejemplo n.º 2
0
    def testCheckeredPigment(self):
        color1 = Color(1.0, 2.0, 3.0)
        color2 = Color(10.0, 20.0, 30.0)

        pigment = CheckeredPigment(color1=color1,
                                   color2=color2,
                                   num_of_steps=2)

        # With num_of_steps == 2, the pattern should be the following:
        #
        #              (0.5, 0)
        #   (0, 0) +------+------+ (1, 0)
        #          |      |      |
        #          | col1 | col2 |
        #          |      |      |
        # (0, 0.5) +------+------+ (1, 0.5)
        #          |      |      |
        #          | col2 | col1 |
        #          |      |      |
        #   (0, 1) +------+------+ (1, 1)
        #              (0.5, 1)
        assert pigment.get_color(Vec2d(0.25, 0.25)).is_close(color1)
        assert pigment.get_color(Vec2d(0.75, 0.25)).is_close(color2)
        assert pigment.get_color(Vec2d(0.25, 0.75)).is_close(color2)
        assert pigment.get_color(Vec2d(0.75, 0.75)).is_close(color1)
Ejemplo n.º 3
0
    def testHit(self):
        sphere = Sphere()

        ray1 = Ray(origin=Point(0, 0, 2), dir=-VEC_Z)
        intersection1 = sphere.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(0.0, 0.0, 1.0),
            normal=Normal(0.0, 0.0, 1.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=sphere.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(3, 0, 0), dir=-VEC_X)
        intersection2 = sphere.ray_intersection(ray2)
        assert intersection2
        assert HitRecord(
            world_point=Point(1.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=2.0,
            ray=ray2,
            material=sphere.material,
        ).is_close(intersection2)

        assert not sphere.ray_intersection(
            Ray(origin=Point(0, 10, 2), dir=-VEC_Z))
Ejemplo n.º 4
0
    def testUniformPigment(self):
        color = Color(1.0, 2.0, 3.0)
        pigment = UniformPigment(color=color)

        assert pigment.get_color(Vec2d(0.0, 0.0)).is_close(color)
        assert pigment.get_color(Vec2d(1.0, 0.0)).is_close(color)
        assert pigment.get_color(Vec2d(0.0, 1.0)).is_close(color)
        assert pigment.get_color(Vec2d(1.0, 1.0)).is_close(color)
Ejemplo n.º 5
0
    def testUVCoordinates(self):
        plane = Plane()

        ray1 = Ray(origin=Point(0, 0, 1), dir=-VEC_Z)
        intersection1 = plane.ray_intersection(ray1)
        assert intersection1.surface_point.is_close(Vec2d(0.0, 0.0))

        ray2 = Ray(origin=Point(0.25, 0.75, 1), dir=-VEC_Z)
        intersection2 = plane.ray_intersection(ray2)
        assert intersection2.surface_point.is_close(Vec2d(0.25, 0.75))

        ray3 = Ray(origin=Point(4.25, 7.75, 1), dir=-VEC_Z)
        intersection3 = plane.ray_intersection(ray3)
        assert intersection3.surface_point.is_close(Vec2d(0.25, 0.75))
Ejemplo n.º 6
0
    def testTransformation(self):
        plane = Plane(transformation=rotation_y(angle_deg=90.0))

        ray1 = Ray(origin=Point(1, 0, 0), dir=-VEC_X)
        intersection1 = plane.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(0.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=plane.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(0, 0, 1), dir=VEC_Z)
        intersection2 = plane.ray_intersection(ray2)
        assert not intersection2

        ray3 = Ray(origin=Point(0, 0, 1), dir=VEC_X)
        intersection3 = plane.ray_intersection(ray3)
        assert not intersection3

        ray4 = Ray(origin=Point(0, 0, 1), dir=VEC_Y)
        intersection4 = plane.ray_intersection(ray4)
        assert not intersection4
Ejemplo n.º 7
0
    def testImagePigment(self):
        image = HdrImage(width=2, height=2)
        image.set_pixel(0, 0, Color(1.0, 2.0, 3.0))
        image.set_pixel(1, 0, Color(2.0, 3.0, 1.0))
        image.set_pixel(0, 1, Color(2.0, 1.0, 3.0))
        image.set_pixel(1, 1, Color(3.0, 2.0, 1.0))

        pigment = ImagePigment(image)
        assert pigment.get_color(Vec2d(0.0,
                                       0.0)).is_close(Color(1.0, 2.0, 3.0))
        assert pigment.get_color(Vec2d(1.0,
                                       0.0)).is_close(Color(2.0, 3.0, 1.0))
        assert pigment.get_color(Vec2d(0.0,
                                       1.0)).is_close(Color(2.0, 1.0, 3.0))
        assert pigment.get_color(Vec2d(1.0,
                                       1.0)).is_close(Color(3.0, 2.0, 1.0))
Ejemplo n.º 8
0
def _sphere_point_to_uv(point: Point) -> Vec2d:
    """Convert a 3D point on the surface of the unit sphere into a (u, v) 2D point"""
    u = atan2(point.y, point.x) / (2.0 * pi)
    return Vec2d(
        u=u if u >= 0.0 else u + 1.0,
        v=acos(point.z) / pi,
    )
Ejemplo n.º 9
0
    def ray_intersection(self, ray: Ray) -> Union[HitRecord, None]:
        """Checks if a ray intersects the plane

        Return a `HitRecord`, or `None` if no intersection was found.
        """
        inv_ray = ray.transform(self.transformation.inverse())
        if abs(inv_ray.dir.z) < 1e-5:
            return None

        t = -inv_ray.origin.z / inv_ray.dir.z

        if (t <= inv_ray.tmin) or (t >= inv_ray.tmax):
            return None

        hit_point = inv_ray.at(t)

        return HitRecord(
            world_point=self.transformation * hit_point,
            normal=self.transformation *
            Normal(0.0, 0.0, 1.0 if inv_ray.dir.z < 0.0 else -1.0),
            surface_point=Vec2d(hit_point.x - floor(hit_point.x),
                                hit_point.y - floor(hit_point.y)),
            t=t,
            ray=ray,
            material=self.material,
        )
Ejemplo n.º 10
0
    def testInnerHit(self):
        sphere = Sphere()

        ray = Ray(origin=Point(0, 0, 0), dir=VEC_X)
        intersection = sphere.ray_intersection(ray)
        assert intersection
        assert HitRecord(
            world_point=Point(1.0, 0.0, 0.0),
            normal=Normal(-1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=1.0,
            ray=ray,
        ).is_close(intersection)
Ejemplo n.º 11
0
    def testUVCoordinates(self):
        sphere = Sphere()

        # The first four rays hit the unit sphere at the
        # points P1, P2, P3, and P4.
        #
        #                    ^ y
        #                    | P2
        #              , - ~ * ~ - ,
        #          , '       |       ' ,
        #        ,           |           ,
        #       ,            |            ,
        #      ,             |             , P1
        # -----*-------------+-------------*---------> x
        #   P3 ,             |             ,
        #       ,            |            ,
        #        ,           |           ,
        #          ,         |        , '
        #            ' - , _ * _ ,  '
        #                    | P4
        #
        # P5 and P6 are aligned along the x axis and are displaced
        # along z (ray5 in the positive direction, ray6 in the negative
        # direction).

        ray1 = Ray(origin=Point(2.0, 0.0, 0.0), dir=-VEC_X)
        assert sphere.ray_intersection(ray1).surface_point.is_close(
            Vec2d(0.0, 0.5))

        ray2 = Ray(origin=Point(0.0, 2.0, 0.0), dir=-VEC_Y)
        assert sphere.ray_intersection(ray2).surface_point.is_close(
            Vec2d(0.25, 0.5))

        ray3 = Ray(origin=Point(-2.0, 0.0, 0.0), dir=VEC_X)
        assert sphere.ray_intersection(ray3).surface_point.is_close(
            Vec2d(0.5, 0.5))

        ray4 = Ray(origin=Point(0.0, -2.0, 0.0), dir=VEC_Y)
        assert sphere.ray_intersection(ray4).surface_point.is_close(
            Vec2d(0.75, 0.5))

        ray5 = Ray(origin=Point(2.0, 0.0, 0.5), dir=-VEC_X)
        assert sphere.ray_intersection(ray5).surface_point.is_close(
            Vec2d(0.0, 1 / 3))

        ray6 = Ray(origin=Point(2.0, 0.0, -0.5), dir=-VEC_X)
        assert sphere.ray_intersection(ray6).surface_point.is_close(
            Vec2d(0.0, 2 / 3))