示例#1
0
    def test_refraction__standard(self):
        """Test that we return the correct color under normal refraction"""

        world = copy.deepcopy(self.default_scene)

        # s1 = A
        s1 = world.objects[1]
        s1.material.ambient = 1.0
        s1.material.pattern = patterns.TestPattern()

        # s2 = B
        s2 = world.objects[0]
        s2.material.transparency = 1.0
        s2.material.refractive_index = 1.5

        r = rays.Ray(points.Point(0, 0, 0.1), vectors.Vector(0, 1, 0))

        xs = intersections.Intersections(
            intersections.Intersection(s1, -0.9899),
            intersections.Intersection(s2, -0.4899),
            intersections.Intersection(s2, 0.4899),
            intersections.Intersection(s1, 0.9899))

        # Intersections[2] because the first two are behind the camera
        comps = xs.intersections[2].precompute(r, all_intersections=xs)

        result, _ = world.refracted_color(comps, 5)

        # Remember the test pattern returns the x, y, z coordinates of the
        # input point as the color so we can inspect positions
        self.assertEqual(result, colors.Color(0, 0.99888, 0.0475))
示例#2
0
    def test_reflection__reflective(self):
        """Test the reflection color of a reflective material is not black"""

        p = shapes.Plane(material=materials.Material(reflective=0.5))
        p.set_transform(transforms.Translate(0, -1, 0))

        world = copy.deepcopy(self.default_scene)

        world.objects.append(p)

        r = rays.Ray(points.Point(0, 0, -3),
                     vectors.Vector(0, -math.sqrt(2) / 2,
                                    math.sqrt(2) / 2))

        i = intersections.Intersection(p, math.sqrt(2))

        comps = i.precompute(r)

        # Test reflected color alone
        result, _ = world.reflected_color(comps)
        self.assertEqual(result, colors.Color(0.19032, 0.2379, 0.14274))

        # Now test the reflected color is added to the surface color
        result, _ = world.shade_hit(comps)
        self.assertEqual(result, colors.Color(0.87677, 0.92436, 0.82918))
示例#3
0
    def test_reflective_transparent_material(self):
        """Test shade_hit with a reflective, transparent material"""

        world = copy.deepcopy(self.default_scene)

        floor = shapes.Plane(material=materials.Material(
            reflective=0.5, transparency=0.5, refractive_index=1.5))
        floor.set_transform(transforms.Translate(0, -1, 0))

        ball = shapes.Sphere(material=materials.Material(
            color=colors.Color(1, 0, 0), ambient=0.5))
        ball.set_transform(transforms.Translate(0, -3.5, -0.5))

        r = rays.Ray(points.Point(0, 0, -3),
                     vectors.Vector(0, -math.sqrt(2) / 2,
                                    math.sqrt(2) / 2))
        xs = intersections.Intersections(
            intersections.Intersection(floor, math.sqrt(2)))

        world.add_object(floor)
        world.add_object(ball)

        comps = xs.intersections[0].precompute(r, all_intersections=xs)

        color, _ = world.shade_hit(comps, remaining=5)

        self.assertEqual(color, colors.Color(0.93391, 0.69643, 0.69243))
示例#4
0
    def test_intersection_miss(self):
        """Test we handle the case where the ray misses the sphere"""

        s = shapes.Sphere()
        r = rays.Ray(points.Point(0, 2, -5), vectors.Vector(0, 0, 1))

        self.assertEqual(s.intersect(r).intersections, [])
示例#5
0
    def test_shadows__full_scene(self):
        """Test that we identify a shadow in a full scene"""

        # First sphere is at z=10
        s1 = shapes.Sphere()
        s1.set_transform(transforms.Translate(0, 0, 10))

        # Second sphere is at the origin
        s2 = shapes.Sphere()
        s2.material = materials.Material()

        # Light is at z=-10
        l1 = lights.Light(position=points.Point(0, 0, -10),
                          intensity=colors.Color(1, 1, 1))

        scene = scenes.Scene(objects=[s1, s2], lights=[l1])

        # The ray is at z=5 (i.e. between the spheres), pointing at the further
        # out sphere
        ray = rays.Ray(points.Point(0, 0, 5), vectors.Vector(0, 0, 1))

        isection = intersections.Intersection(s2, 4)
        comps = isection.precompute(ray)

        result, _ = scene.shade_hit(comps)

        self.assertEqual(result, colors.Color(0.1, 0.1, 0.1))
示例#6
0
    def test_refraction__total_internal_reflection(self):
        """Test that we return black if we hit total internal reflection"""

        world = copy.deepcopy(self.default_scene)

        s = world.objects[1]

        s.material.transparency = 1.0
        s.material.refractive_index = 1.5

        r = rays.Ray(points.Point(0, 0,
                                  math.sqrt(2) / 2), vectors.Vector(0, 1, 0))

        xs = intersections.Intersections(
            intersections.Intersection(s, -math.sqrt(2) / 2),
            intersections.Intersection(s,
                                       math.sqrt(2) / 2))

        # n.b. the camera is inside the inner-sphere so use the second
        # intersection
        comps = xs.intersections[1].precompute(r, all_intersections=xs)

        result, _ = world.refracted_color(comps, 5)

        self.assertEqual(result, colors.Color(0, 0, 0))
示例#7
0
    def test_local_intersect(self):
        """Test we can calculate where a ray intersects with a plane"""

        p = shapes.Plane()

        # Rays parallel with the plane
        r = rays.Ray(points.Point(0, 10, 0), vectors.Vector(0, 0, 1))
        xs = p.local_intersect(r)
        self.assertEqual(len(xs.intersections), 0)

        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 0, 1))
        xs = p.local_intersect(r)
        self.assertEqual(len(xs.intersections), 0)

        # Rays that do intersect the plane
        r = rays.Ray(points.Point(0, 1, 0), vectors.Vector(0, -1, 0))
        xs = p.local_intersect(r)
        self.assertEqual(xs.intersections[0].t, 1)
示例#8
0
    def test_intersect_scene(self):
        """Test that we can intersect an entire scene"""

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = self.default_scene.intersect(r)

        ts = [x.t for x in result.intersections]
        self.assertEqual(ts, [4, 4.5, 5.5, 6])
    def test_refractive_index_intersections(self):
        """Test we can calculate the refractive indices between intersections"""

        # Set up a scene with three glass spheres.  One at the origin with size
        # 2 then inside of that 2 that are offset along z by different amounts
        A = shapes.Sphere(material=materials.Material(refractive_index=1.5,
                                                      transparency=1.0))
        B = shapes.Sphere(material=materials.Material(refractive_index=2.0,
                                                      transparency=1.0))
        C = shapes.Sphere(material=materials.Material(refractive_index=2.5,
                                                      transparency=1.0))

        A.set_transform(transforms.Scale(2, 2, 2))
        B.set_transform(transforms.Translate(0, 0, -0.25))
        C.set_transform(transforms.Translate(0, 0, 0.25))

        r = rays.Ray(points.Point(0, 0, -4), vectors.Vector(0, 0, 1))

        xs = intersections.Intersections(intersections.Intersection(A, 2),
                                         intersections.Intersection(B, 2.75),
                                         intersections.Intersection(C, 3.25),
                                         intersections.Intersection(B, 4.75),
                                         intersections.Intersection(C, 5.25),
                                         intersections.Intersection(A, 6))

        expected_results = [
            {
                "n1": 1.0,
                "n2": 1.5
            },
            {
                "n1": 1.5,
                "n2": 2.0
            },
            {
                "n1": 2.0,
                "n2": 2.5
            },
            {
                "n1": 2.5,
                "n2": 2.5
            },
            {
                "n1": 2.5,
                "n2": 1.5
            },
            {
                "n1": 1.5,
                "n2": 1.0
            },
        ]

        for index, expected in enumerate(expected_results):

            comps = xs.intersections[index].precompute(r, all_intersections=xs)
            self.assertDictEqual(expected, {"n1": comps.n1, "n2": comps.n2})
示例#10
0
    def test_position(self):

        origin = points.Point(2, 3, 4)
        direction = vectors.Vector(1, 0, 0)
        r = rays.Ray(origin, direction)

        self.assertEqual(r.position(0), origin)
        self.assertEqual(r.position(1), points.Point(3, 3, 4))
        self.assertEqual(r.position(-1), points.Point(1, 3, 4))
        self.assertEqual(r.position(2.5), points.Point(4.5, 3, 4))
示例#11
0
    def test_intersection_standard(self):
        """Test we can identify what points a ray intersects with a sphere"""
        s = shapes.Sphere()
        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)

        self.assertEqual(result.intersections[0].t, 4)
        self.assertEqual(result.intersections[1].t, 6)
        self.assertEqual(result.intersections[0].shape, s)
        self.assertEqual(result.intersections[1].shape, s)
示例#12
0
    def test_intersection_behind(self):
        """Test we handle the case where the ray starts inside the sphere"""

        s = shapes.Sphere()
        r = rays.Ray(points.Point(0, 0, 5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)

        self.assertEqual(result.intersections[0].t, -6)
        self.assertEqual(result.intersections[1].t, -4)
        self.assertEqual(result.intersections[0].shape, s)
        self.assertEqual(result.intersections[1].shape, s)
示例#13
0
    def test_intersections_with_transformed_ray__translation(self):
        """Test we get the correct intersections after adding a translation
        to a shape
        """

        s = shapes.Sphere()
        s.set_transform(transforms.Translate(5, 0, 0))

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)
        self.assertTrue(len(result.intersections) == 0)
示例#14
0
    def test_schlick__small_angle(self):
        """Test that we calculate the reflectance at a small angle
        """

        r = rays.Ray(points.Point(0, 0.99, -2), vectors.Vector(0, 0, 1))

        xs = intersections.Intersections(
            intersections.Intersection(self.glass_sphere, 1.8589), )

        comps = xs.intersections[0].precompute(r, all_intersections=xs)

        self.assertAlmostEqual(comps.schlick, 0.48873081)
示例#15
0
    def test_color_at(self):
        """Tests on the color_at function"""

        # The ray points away from the object
        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 1, 0))
        self.assertEqual(
            self.default_scene.color_at(r)[0], colors.Color(0, 0, 0))

        # The ray points at the outer sphere
        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))
        self.assertEqual(
            self.default_scene.color_at(r)[0],
            colors.Color(0.38066, 0.47583, 0.2855))

        # The ray is outside the inner sphere, but inside the outer sphere,
        # pointing in.  It should return the color of the inner sphere
        scene = copy.deepcopy(self.default_scene)
        scene.objects[0].material.ambient = 1
        scene.objects[1].material.ambient = 1
        r = rays.Ray(points.Point(0, 0, 0.75), vectors.Vector(0, 0, -1))
        self.assertEqual(scene.color_at(r)[0], scene.objects[0].material.color)
示例#16
0
    def test_schlick__perpendicular(self):
        """Test that we calculate the reflectance for a perpendicular ray
        """

        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 1, 0))

        xs = intersections.Intersections(
            intersections.Intersection(self.glass_sphere, -1),
            intersections.Intersection(self.glass_sphere, 1))

        comps = xs.intersections[1].precompute(r, all_intersections=xs)

        self.assertAlmostEqual(comps.schlick, 0.04)
示例#17
0
    def test_shade_hit__outside(self):
        """Test that we shade an individual hit the correct color when outside
        an object"""

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        shape = self.default_scene.objects[1]

        i = intersections.Intersection(shape, 4)
        computations = i.precompute(r)

        color, _ = self.default_scene.shade_hit(computations)
        self.assertEqual(color, colors.Color(0.38066, 0.47583, 0.2855))
示例#18
0
    def test_ray_transforms(self):
        """Test that we can transform a ray"""

        origin = points.Point(1, 2, 3)
        direction = vectors.Vector(0, 1, 0)
        r = rays.Ray(origin, direction)

        r2 = r.transform(transforms.Translate(3, 4, 5))
        self.assertEqual(r2.origin, points.Point(4, 6, 8))
        self.assertEqual(r2.direction, vectors.Vector(0, 1, 0))

        r3 = r.transform(transforms.Scale(2, 3, 4))
        self.assertEqual(r3.origin, points.Point(2, 6, 12))
        self.assertEqual(r3.direction, vectors.Vector(0, 3, 0))
示例#19
0
    def test_precompute__inside(self):
        """Test that we can precompute vectors for an intersection and ray when
        inside of a shape"""

        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 0, 1))
        s = shapes.Sphere()
        i = intersections.Intersection(s, 1)

        computations = i.precompute(r)

        self.assertEqual(computations.t, 1)
        self.assertEqual(computations.point, points.Point(0, 0, 1))
        self.assertEqual(computations.eyev, vectors.Vector(0, 0, -1))
        self.assertEqual(computations.normalv, vectors.Vector(0, 0, -1))
        self.assertTrue(computations.inside)
示例#20
0
    def test_precompute_reflectv(self):
        """Test that we can calculate the reflection vector"""

        p = shapes.Plane()
        r = rays.Ray(points.Point(0, 1, -1),
                     vectors.Vector(0, -math.sqrt(2) / 2,
                                    math.sqrt(2) / 2))
        i = intersections.Intersection(p, math.sqrt(2))

        comps = i.precompute(r)

        self.assertEqual(comps.reflectv,
                         vectors.Vector(0,
                                        math.sqrt(2) / 2,
                                        math.sqrt(2) / 2))
示例#21
0
    def test_precompute__over_vector(self):
        """Test that we calculate a vector just inside of the surface of a
        shape
        """

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        s = shapes.Sphere()
        s.set_transform(transforms.Translate(0, 0, 1))

        i = intersections.Intersection(s, 5)

        computations = i.precompute(r)
        self.assertTrue(computations.under_point.z > computations.point.z)
        self.assertTrue(computations.under_point.z > intersections.EPSILON / 2)
示例#22
0
    def test_intersections_with_transformed_ray__scaling(self):
        """Test we get the correct intersections after adding a scaling
        to a shape
        """

        s = shapes.Sphere()
        s.set_transform(transforms.Scale(2, 2, 2))

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        result = s.intersect(r)
        self.assertEqual(result.intersections[0].t, 3)
        self.assertEqual(result.intersections[1].t, 7)
        self.assertEqual(result.intersections[0].shape, s)
        self.assertEqual(result.intersections[1].shape, s)
示例#23
0
    def is_shadowed(self, point: points.Point, light: lights.Light) -> bool:
        """Returns True if the point is shadowed from the light"""

        v = light.position - point
        distance = v.magnitude()
        direction = v.normalize()

        ray = rays.Ray(point, direction)
        intersections = self.intersect(ray)

        hit = intersections.hit()

        if hit is not None and hit.t < distance:
            return True

        return False
示例#24
0
    def test_schlick__total_internal_reflection(self):
        """Test that we calculate the reflectance under total internal
        reflection
        """

        r = rays.Ray(points.Point(0, 0,
                                  math.sqrt(2) / 2), vectors.Vector(0, 1, 0))

        xs = intersections.Intersections(
            intersections.Intersection(self.glass_sphere, -math.sqrt(2) / 2),
            intersections.Intersection(self.glass_sphere,
                                       math.sqrt(2) / 2))

        comps = xs.intersections[1].precompute(r, all_intersections=xs)

        self.assertEqual(comps.schlick, 1)
示例#25
0
    def ray_for_pixel(self, pixel_x: int, pixel_y: int) -> rays.Ray:
        """Given the x and y indices of a pixel, get the ray that is fired"""

        xoffset = (pixel_x + 0.5) * self.pixel_size
        yoffset = (pixel_y + 0.5) * self.pixel_size

        world_x = self.half_width - xoffset
        world_y = self.half_height - yoffset

        # Using the camera's transform, change the canvas point and origin.
        # remember the canvas is at z=-1
        pixel = self.transform.inverse() * points.Point(world_x, world_y, -1)
        origin = self.transform.inverse() * points.Point(0, 0, 0)
        direction = (pixel - origin).normalize()

        return rays.Ray(origin, direction)
示例#26
0
    def test_refraction__opaque(self):
        """Test the refraction color of an opaque material is black"""

        world = copy.deepcopy(self.default_scene)

        s = world.objects[1]

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        xs = intersections.Intersections(intersections.Intersection(s, 4),
                                         intersections.Intersection(s, 6))

        comps = xs.intersections[0].precompute(r, all_intersections=xs)

        result, _ = world.refracted_color(comps, 5)

        self.assertEqual(result, colors.Color(0, 0, 0))
示例#27
0
    def test_shade_hit__inside(self):
        """Test that we shade an individual hit the correct color when inside
        an object"""

        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 0, 1))

        self.default_scene.lights = [
            lights.PointLight(points.Point(0, 0.25, 0), colors.Color(1, 1, 1))
        ]

        shape = self.default_scene.objects[0]

        i = intersections.Intersection(shape, 0.5)
        computations = i.precompute(r)

        color, _ = self.default_scene.shade_hit(computations)

        self.assertEqual(color, colors.Color(0.90498, 0.90498, 0.90498))
示例#28
0
    def test_reflection__non_reflective(self):
        """Test the reflection color of a nonreflective material is not black"""

        world = copy.deepcopy(self.default_scene)

        s = world.objects[0]
        s.material.ambient = 1

        # The ray is inside the inner sphere of the default scene
        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 0, 1))

        i = intersections.Intersection(s, 1)

        comps = i.precompute(r)

        result, _ = world.reflected_color(comps)

        self.assertEqual(result, colors.Color(0, 0, 0))
示例#29
0
    def test_refraction__recursion_limit(self):
        """Test that we return black if we hit the refraction limit"""

        world = copy.deepcopy(self.default_scene)

        s = world.objects[1]

        s.material.transparency = 1.0
        s.material.refractive_index = 1.5

        r = rays.Ray(points.Point(0, 0, -5), vectors.Vector(0, 0, 1))

        xs = intersections.Intersections(intersections.Intersection(s, 4),
                                         intersections.Intersection(s, 6))

        comps = xs.intersections[0].precompute(r, all_intersections=xs)

        result, _ = world.refracted_color(comps, 0)

        self.assertEqual(result, colors.Color(0, 0, 0))
示例#30
0
    def test_reflection__infinite_recursion(self):
        """Test that we don't break if there is infinite recursion"""

        # Two parallel planes
        s1 = shapes.Plane(material=materials.Material(reflective=1))
        s1.set_transform(transforms.Translate(0, -1, 0))

        # Second sphere is at the origin
        s2 = shapes.Plane(material=materials.Material(reflective=1))
        s2.set_transform(transforms.Translate(0, 1, 0))

        # Light is at z=-10
        l1 = lights.Light(position=points.Point(0, 0, 0),
                          intensity=colors.Color(1, 1, 1))

        scene = scenes.Scene(objects=[s1, s2], lights=[l1])

        r = rays.Ray(points.Point(0, 0, 0), vectors.Vector(0, 1, 0))

        # If this is working the following will NOT cause a stack trace
        scene.color_at(r)