Ejemplo n.º 1
0
    def local_intersect(self, ray):
        if len(self.children) == 0:
            return Intersections()

        xs = reduce(lambda a, e: a + e.intersect(ray).sorted_intersections,
                    self.children, [])
        return Intersections(*xs)
Ejemplo n.º 2
0
    def local_intersect(self, ray):
        def check_axis(origin, direction):
            tmin_numerator = (-1 - origin)
            tmax_numerator = (1 - origin)

            if abs(direction) >= EPSILON:
                tmin = tmin_numerator / direction
                tmax = tmax_numerator / direction
            else:
                tmin = tmin_numerator * float('inf')
                tmax = tmax_numerator * float('inf')

            if tmin > tmax:
                tmin, tmax = tmax, tmin

            return (tmin, tmax)

        xtmin, xtmax = check_axis(ray.origin.x, ray.direction.x)
        ytmin, ytmax = check_axis(ray.origin.y, ray.direction.y)
        ztmin, ztmax = check_axis(ray.origin.z, ray.direction.z)

        tmin = max(xtmin, ytmin, ztmin)
        tmax = min(xtmax, ytmax, ztmax)

        if tmin > tmax:
            return Intersections()
        else:
            return Intersections(Intersection(tmin, self),
                                 Intersection(tmax, self))
Ejemplo n.º 3
0
    def local_intersect(self, ray):
        a = ray.direction.x**2 - ray.direction.y**2 + ray.direction.z**2
        b = 2 * ray.origin.x * ray.direction.x \
            - 2 * ray.origin.y * ray.direction.y \
            + 2 * ray.origin.z * ray.direction.z
        c = ray.origin.x**2 - ray.origin.y**2 + ray.origin.z**2

        if abs(a) < EPSILON:
            if abs(b) < EPSILON:
                return Intersections()
            else:
                xs = [Intersection(-c / (2 * b), self)] + \
                    self._intersect_caps(ray)
                return Intersections(*xs)

        disc = b**2 - 4 * a * c
        if disc < 0:
            return Intersections()

        t0 = (-b - sqrt(disc)) / (2 * a)
        t1 = (-b + sqrt(disc)) / (2 * a)

        xs = []

        y0 = ray.origin.y + t0 * ray.direction.y
        if self.minimum < y0 and y0 < self.maximum:
            xs.append(Intersection(t0, self))

        y1 = ray.origin.y + t1 * ray.direction.y
        if self.minimum < y1 and y1 < self.maximum:
            xs.append(Intersection(t1, self))

        xs = xs + self._intersect_caps(ray)

        return Intersections(*xs)
Ejemplo n.º 4
0
def test_the_hit__when_all_intersections_have_positive_t():
    # Given
    s = Sphere()
    i1 = Intersection(1, s)
    i2 = Intersection(2, s)
    xs = Intersections(i2, i1)
    # When
    i = xs.hit()
    # Then
    assert i == i1
Ejemplo n.º 5
0
def test_the_hit__when_some_intersections_have_negative_t():
    # Given
    s = Sphere()
    i1 = Intersection(-1, s)
    i2 = Intersection(1, s)
    xs = Intersections(i2, i1)
    # When
    i = xs.hit()
    # Then
    assert i == i2
Ejemplo n.º 6
0
def test_the_hit__when_all_intersections_have_netative_t():
    # Given
    s = Sphere()
    i1 = Intersection(-2, s)
    i2 = Intersection(-1, s)
    xs = Intersections(i2, i1)
    # When
    i = xs.hit()
    # Then
    assert i is None
Ejemplo n.º 7
0
def test_the_hit_is_always_the_lowest_nonnegative_intersection():
    # Given
    s = Sphere()
    i1 = Intersection(5, s)
    i2 = Intersection(7, s)
    i3 = Intersection(-3, s)
    i4 = Intersection(2, s)
    xs = Intersections(i1, i2, i3, i4)
    # When
    i = xs.hit()
    # Then
    assert i == i4
Ejemplo n.º 8
0
    def local_intersect(self, ray):
        # the vector from the sphere's center, to the ray origin
        # remember: the sphere is centered at the world origin
        sphere_to_ray = ray.origin - Point(0, 0, 0)

        a = ray.direction.dot(ray.direction)
        b = 2 * 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()

        t1 = (-b - sqrt(discriminant)) / (2 * a)
        t2 = (-b + sqrt(discriminant)) / (2 * a)
        return Intersections(Intersection(t1, self), Intersection(t2, self))
Ejemplo n.º 9
0
def test_the_schlick_approximation_with_small_angle_and_n2_greater_than_n1():
    # Given
    shape = glass_sphere()
    r = Ray(Point(0, 0.99, -2), Vector(0, 0, 1))
    xs = Intersections(Intersection(1.8589, shape))
    # When
    comps = xs[0].prepare_computations(r, xs)
    reflectance = comps.schlick()
    # Then
    assert equal(reflectance, 0.48873)
Ejemplo n.º 10
0
def test_the_schlick_approximation_with_a_perpendicular_viewing_angle():
    # Given
    shape = glass_sphere()
    r = Ray(Point(0, 0, 0), Vector(0, 1, 0))
    xs = Intersections(Intersection(-1, shape), Intersection(1, shape))
    # When
    comps = xs[1].prepare_computations(r, xs)
    reflectance = comps.schlick()
    # Then
    assert equal(reflectance, 0.04)
Ejemplo n.º 11
0
def test_the_refracted_color_with_an_opaque_surface():
    # Given
    w = default_world()
    shape = w.objects[0]
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    xs = Intersections(Intersection(4, shape), Intersection(6, shape))
    # When
    comps = xs[0].prepare_computations(r, xs)
    c = w.refracted_color(comps, 5)
    # Then
    assert c == Color(0, 0, 0)
Ejemplo n.º 12
0
def test_the_schlick_approximation_under_total_internal_reflection():
    # Given
    shape = glass_sphere()
    r = Ray(Point(0, 0, sqrt(2) / 2), Vector(0, 1, 0))
    xs = Intersections(Intersection(-sqrt(2) / 2, shape),
                       Intersection(sqrt(2) / 2, shape))
    # When
    comps = xs[1].prepare_computations(r, xs)
    reflectance = comps.schlick()
    # Then
    assert reflectance == 1.0
Ejemplo n.º 13
0
def test_aggregating_intersections():
    # Given
    s = Sphere()
    i1 = Intersection(1, s)
    i2 = Intersection(2, s)
    # When
    xs = Intersections(i1, i2)
    # Then
    assert len(xs) == 2
    assert xs[0].t == 1
    assert xs[1].t == 2
Ejemplo n.º 14
0
def test_the_under_point_is_offset_below_the_surface():
    # Given
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = glass_sphere()
    shape.transform = translation(0, 0, 1)
    i = Intersection(5, shape)
    xs = Intersections(i)
    # When
    comps = i.prepare_computations(r, xs)
    # Then
    assert comps.under_point.z > EPSILON / 2
    assert comps.point.z < comps.under_point.z
Ejemplo n.º 15
0
def test_the_refracted_color_at_the_maximum_recursive_depth():
    # Given
    w = default_world()
    shape = w.objects[0]
    shape.material.transparency = 1.0
    shape.material.refractive_index = 1.5
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    xs = Intersections(Intersection(4, shape), Intersection(6, shape))
    # When
    comps = xs[0].prepare_computations(r, xs)
    c = w.refracted_color(comps, 0)
    # Then
    assert c == Color(0, 0, 0)
Ejemplo n.º 16
0
def test_finding_n1_and_n2_at_various_intersections():
    # Given
    A = glass_sphere()
    A.transform = scaling(2, 2, 2)
    A.material.refractive_index = 1.5

    B = glass_sphere()
    B.transform = translation(0, 0, -0.25)
    B.material.refractive_index = 2.0

    C = glass_sphere()
    C.transform = translation(0, 0, 0.25)
    C.material.refractive_index = 2.5

    r = Ray(Point(0, 0, -4), Vector(0, 0, 1))
    xs = Intersections(Intersection(2, A), Intersection(2.75, B),
                       Intersection(3.25, C), Intersection(4.75, B),
                       Intersection(5.25, C), Intersection(6, A))
    EXAMPLES = [
        {
            'n1': 1.0,
            'n2': 1.5
        },  # index: 0
        {
            'n1': 1.5,
            'n2': 2.0
        },  # index: 1
        {
            'n1': 2.0,
            'n2': 2.5
        },  # index: 2
        {
            'n1': 2.5,
            'n2': 2.5
        },  # index: 3
        {
            'n1': 2.5,
            'n2': 1.5
        },  # index: 4
        {
            'n1': 1.5,
            'n2': 1.0
        },  # index: 5
    ]
    for index in range(len(EXAMPLES)):
        # When
        comps = xs[index].prepare_computations(r, xs=xs)
        # Then
        assert comps.n1 == EXAMPLES[index]['n1']
        assert comps.n2 == EXAMPLES[index]['n2']
Ejemplo n.º 17
0
    def local_intersect(self, ray):
        a = ray.direction.x ** 2 + ray.direction.z ** 2

        # ray is parallel to the y axis
        if abs(a) < EPSILON:
            xs = self._intersect_caps(ray)
            return Intersections(*xs)

        b = 2 * ray.origin.x * ray.direction.x + \
            2 * ray.origin.z * ray.direction.z
        c = ray.origin.x ** 2 + ray.origin.z ** 2 - 1
        disc = b ** 2 - 4 * a * c

        # ray does not intersect the cylinder
        if disc < 0:
            return Intersections()

        t0 = (-b - sqrt(disc)) / (2 * a)
        t1 = (-b + sqrt(disc)) / (2 * a)

        # if t0 > t1:
        #     t0, t1 = t1, t0

        xs = []

        y0 = ray.origin.y + t0 * ray.direction.y
        if self.minimum < y0 and y0 < self.maximum:
            xs.append(Intersection(t0, self))

        y1 = ray.origin.y + t1 * ray.direction.y
        if self.minimum < y1 and y1 < self.maximum:
            xs.append(Intersection(t1, self))

        xs = xs + self._intersect_caps(ray)

        return Intersections(*xs)
Ejemplo n.º 18
0
def test_the_refracted_color_under_total_internal_reflection():
    # Given
    w = default_world()
    shape = w.objects[0]
    shape.material.transparency = 1.0
    shape.material.refractive_index = 1.5
    r = Ray(Point(0, 0, sqrt(2) / 2), Vector(0, 1, 0))
    xs = Intersections(Intersection(-sqrt(2) / 2, shape),
                       Intersection(sqrt(2) / 2, shape))
    # When

    # NOTE: this time you're inside the sphere, so you need
    # to look at the second intersection, xs[1], not xs[0]
    comps = xs[1].prepare_computations(r, xs)
    c = w.refracted_color(comps, 5)
    # Then
    assert c == Color(0, 0, 0)
Ejemplo n.º 19
0
def test_refracted_color_with_a_refracted_ray():
    # Then
    w = default_world()

    A = w.objects[0]
    A.material.ambient = 1.0
    A.material.pattern = MockPattern()

    B = w.objects[1]
    B.material.transparency = 1.0
    B.material.refractive_index = 1.5

    r = Ray(Point(0, 0, 0.1), Vector(0, 1, 0))
    xs = Intersections(Intersection(-0.9899, A), Intersection(-0.4899, B),
                       Intersection(0.4899, B), Intersection(0.9899, A))
    # When
    comps = xs[2].prepare_computations(r, xs)
    c = w.refracted_color(comps, 5)
    # Then
    assert c == Color(0, 0.99887, 0.04721)
Ejemplo n.º 20
0
def test__shade_hit__with_a_transparent_material():
    # Given
    w = default_world()

    floor = Plane()
    floor.transform = translation(0, -1, 0)
    floor.material.transparency = 0.5
    floor.material.refractive_index = 1.5
    w.objects.append(floor)

    ball = Sphere()
    ball.material.color = Color(1, 0, 0)
    ball.material.ambient = 0.5
    ball.transform = translation(0, -3.5, -0.5)
    w.objects.append(ball)

    r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    xs = Intersections(Intersection(sqrt(2), floor))
    # When
    comps = xs[0].prepare_computations(r, xs)
    color = w.shade_hit(comps, 5)
    # Then
    assert color == Color(0.93642, 0.68642, 0.68642)
Ejemplo n.º 21
0
 def intersect_world(self, ray):
     xs = [x for object in self.objects for x in object.intersect(ray)]
     return Intersections(*xs)