コード例 #1
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)
コード例 #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))
コード例 #3
0
def precomputing_the_reflection_vector():
    # Given
    shape = Plane()
    r = Ray(Point(0, 1, -1), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    i = Intersection(sqrt(2), shape)
    # When
    comps = i.prepare_computations(r)
    # Then
    assert comps.reflectv == Vector(0, sqrt(2) / 2, sqrt(2) / 2)
コード例 #4
0
def test_the_hit__when_an_intersection_occurs_on_the_outside():
    # Given
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = Sphere()
    i = Intersection(4, shape)
    # When
    comps = i.prepare_computations(r)
    # Then
    assert comps.inside is False
コード例 #5
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
コード例 #6
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)
コード例 #7
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
コード例 #8
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
コード例 #9
0
def test_shading_an_intersection():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = w.objects[0]
    i = Intersection(4, shape)
    # When
    comps = i.prepare_computations(r)
    c = w.shade_hit(comps)
    # Then
    assert c == Color(0.38066, 0.47583, 0.2855)
コード例 #10
0
def test_the_hit_should_offset_the_point():
    # Given
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = Sphere()
    shape.transform = translation(0, 0, 1)
    i = Intersection(5, shape)
    # When
    comps = i.prepare_computations(r)
    # Then
    assert comps.over_point.z < -EPSILON / 2
    assert comps.point.z > comps.over_point.z
コード例 #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)
コード例 #12
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
コード例 #13
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
コード例 #14
0
def test_the_reflected_color_for_a_nonreflective_material():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, 0), Vector(0, 0, 1))
    shape = Sphere()
    shape.material.ambient = 1
    i = Intersection(1, shape)
    # When
    comps = i.prepare_computations(r)
    color = w.reflected_color(comps)
    # Then
    assert color == Color(0, 0, 0)  # black
コード例 #15
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
コード例 #16
0
def test_the_hit__when_an_intersection_occurs_on_the_inside():
    # Given
    r = Ray(Point(0, 0, 0), Vector(0, 0, 1))
    shape = Sphere()
    i = Intersection(1, shape)
    # When
    comps = i.prepare_computations(r)
    # Then
    assert comps.point == Point(0, 0, 1)
    assert comps.eyev == Vector(0, 0, -1)
    assert comps.inside is True
    assert comps.normalv == Vector(0, 0, -1)
コード例 #17
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
コード例 #18
0
def test_shading_an_intersection_from_the_inside():
    # Given
    w = default_world()
    w.light = PointLight(Point(0, 0.25, 0), Color(1, 1, 1))
    r = Ray(Point(0, 0, 0), Vector(0, 0, 1))
    shape = w.objects[1]
    i = Intersection(0.5, shape)
    # When
    comps = i.prepare_computations(r)
    c = w.shade_hit(comps)
    # Then
    assert c == Color(0.90498, 0.90498, 0.90498)
コード例 #19
0
def test_precomputing_the_state_of_an_intersection():
    # Given
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = Sphere()
    i = Intersection(4, shape)
    # When
    comps = i.prepare_computations(r)
    # Then
    assert comps.t == i.t
    assert comps.object == i.object
    assert comps.point == Point(0, 0, -1)
    assert comps.eyev == Vector(0, 0, -1)
    assert comps.normalv == Vector(0, 0, -1)
コード例 #20
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)
コード例 #21
0
def test_the_reflected_color_at_the_maximum_recursive_depth():
    # Given
    w = default_world()
    shape = Plane()
    shape.material.reflective = 0.5
    shape.transform = translation(0, -1, 0)
    w.objects.append(shape)
    r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    i = Intersection(sqrt(2), shape)
    # When
    comps = i.prepare_computations(r)
    color = w.reflected_color(comps, 0)
    # Then
    assert color == Color(0, 0, 0)
コード例 #22
0
def test__shade_hit__with_a_reflective_material():
    # Given
    w = default_world()
    shape = Plane()
    shape.material.reflective = 0.5
    shape.transform = translation(0, -1, 0)
    w.objects.append(shape)
    r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    i = Intersection(sqrt(2), shape)
    # When
    comps = i.prepare_computations(r)
    color = w.shade_hit(comps)
    # Then
    assert color == Color(0.87675, 0.92434, 0.82918)
コード例 #23
0
def test__shade_hit__is_given_an_intersection_in_shadow():
    # Given
    w = World()
    w.light = PointLight(Point(0, 0, -10), Color(1, 1, 1))
    s1 = Sphere()
    w.objects.append(s1)
    s2 = Sphere()
    s2.transform = translation(0, 0, 10)
    w.objects.append(s2)
    r = Ray(Point(0, 0, 5), Vector(0, 0, 1))
    i = Intersection(4, s2)
    # When
    comps = i.prepare_computations(r)
    c = w.shade_hit(comps)
    # Then
    assert c == Color(0.1, 0.1, 0.1)
コード例 #24
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))
コード例 #25
0
def test_an_intersection_encapsulates_t_and_object():
    # Given
    s = Sphere()
    # When
    i = Intersection(3.5, s)
    # Then
    assert i.t == 3.5
    assert i.object == s
コード例 #26
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)
コード例 #27
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)
コード例 #28
0
    def _intersect_caps(self, ray):
        def check_cap(ray, t):
            x = ray.origin.x + t * ray.direction.x
            z = ray.origin.z + t * ray.direction.z
            return (x ** 2 + z ** 2) <= 1

        xs = []

        if self.closed is False or abs(ray.direction.y) < EPSILON:
            return xs

        t = (self.minimum - ray.origin.y) / ray.direction.y
        if check_cap(ray, t):
            xs.append(Intersection(t, self))

        t = (self.maximum - ray.origin.y) / ray.direction.y
        if check_cap(ray, t):
            xs.append(Intersection(t, self))

        return xs
コード例 #29
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)
コード例 #30
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)