Пример #1
0
    def local_intersect(self, local_ray: rays.Ray):
        """Return the t-value where the ray intersects with the plane, in local
        units
        """

        # If the y-direction of the ray is small it is approximately parallel to
        #the plane, no intersections
        if abs(local_ray.direction.y) < MIN_Y_FOR_PLANE_INTERSECT:
            return intersections.Intersections()

        t = -local_ray.origin.y / local_ray.direction.y
        return intersections.Intersections(intersections.Intersection(self, t))
Пример #2
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))
Пример #3
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))
Пример #4
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))
Пример #5
0
    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})
Пример #6
0
    def test_hits__all_negative(self):
        """Test we get no hits for all negative intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, -1)
        i2 = intersections.Intersection(shape, -2)
        isections = intersections.Intersections(i1, i2)

        self.assertIsNone(isections.hit())
Пример #7
0
    def test_hits__some_negative(self):
        """Test we get the correct hit for some negative intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, -1)
        i2 = intersections.Intersection(shape, 1)
        isections = intersections.Intersections(i1, i2)

        self.assertEqual(isections.hit(), i2)
Пример #8
0
    def test_hits__positive(self):
        """Test we get the correct hit for multiple positive intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, 2)
        i2 = intersections.Intersection(shape, 1)
        isections = intersections.Intersections(i1, i2)

        self.assertEqual(isections.hit(), i2)
Пример #9
0
    def local_intersect(self, local_ray: rays.Ray):
        """Return to t values for where the ray intersects the shape.  All in
        local coordinates for the shape
        """

        sphere_to_ray = local_ray.origin - points.Point(0, 0, 0)

        a = local_ray.direction.dot(local_ray.direction)
        b = 2 * local_ray.direction.dot(sphere_to_ray)
        c = sphere_to_ray.dot(sphere_to_ray) - 1
        discriminant = b**2 - 4 * a * c

        if discriminant < 0:
            return intersections.Intersections()
        else:
            t1 = (-b - math.sqrt(discriminant)) / (2 * a)
            t2 = (-b + math.sqrt(discriminant)) / (2 * a)
            return intersections.Intersections(
                intersections.Intersection(self, t1),
                intersections.Intersection(self, t2))
Пример #10
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)
Пример #11
0
    def test_hits__multiple(self):
        """Test we get the correct hit for some negative intersections"""

        shape = shapes.Sphere()

        i1 = intersections.Intersection(shape, -1)
        i2 = intersections.Intersection(shape, 7)
        i3 = intersections.Intersection(shape, -5)
        i4 = intersections.Intersection(shape, 2)
        i5 = intersections.Intersection(shape, 3)
        isections = intersections.Intersections(i1, i2, i3, i4, i5)

        self.assertEqual(isections.hit(), i4)
Пример #12
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)
Пример #13
0
    def test_initialization(self):

        shape = shapes.Sphere()
        t1 = 3.5
        t2 = -3.5

        i1 = intersections.Intersection(shape, t1)
        self.assertEqual(i1.t, 3.5)
        self.assertEqual(i1.shape, shape)

        i2 = intersections.Intersection(shape, t2)
        self.assertEqual(i2.t, -3.5)

        i = intersections.Intersections(i1, i2)
        self.assertEqual(i.intersections, [i2, i1])
Пример #14
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)
Пример #15
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))
Пример #16
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))