def test_rotate_point_around_z_axis(self): p = Point(0, 1, 0) half_quarter = rotation_z(math.pi / 4) full_quarter = rotation_z(math.pi / 2) assert half_quarter * p == Point(-math.sqrt(2) / 2, math.sqrt(2) / 2, 0) assert full_quarter * p == Point(-1, 0, 0)
def test_chained_transformations_are_in_reverse_order(self): p = Point(1, 0, 1) a = rotation_x(math.pi / 2) b = scaling(5, 5, 5) c = translation(10, 5, 7) t = c * b * a * p assert t == Point(15, 0, 7)
def test_hit_when_intersection_occurs_on_inside(self): r = Ray(Point(0, 0, 0), Vector(0, 0, 1)) shape = Sphere() i = Intersection(1, shape) comps = i.prepare_computations(r) assert comps.point == Point(0, 0, 1) assert comps.eyev == Vector(0, 0, -1) assert comps.inside assert comps.normalv == Vector(0, 0, -1)
def test_render_world_with_camera(self, default_world): w = default_world c = Camera(11, 11, pi / 2) _from = Point(0, 0, -5) to = Point(0, 0, 0) up = Vector(0, 2, 0) c.transformation = view_transform(_from, to, up) image = c.render(w) assert image.pixel_at(5, 5) == Color(0.38066, 0.47583, 0.2855)
def test_shading_intersection_from_inside(self, default_world): w = default_world w.light_source = PointLight(Point(0, 0.25, 0), Color.white()) r = Ray(Point(0, 0, 0), Vector(0, 0, 1)) shape = w.objects[1] i = Intersection(0.5, shape) comps = i.prepare_computations(r) c = w.shade_hit(comps) assert c == Color(0.90498, 0.90498, 0.90498)
def test_arbitrary_view_transformation(self): _from = Point(1, 3, 2) to = Point(4, -2, 8) up = Vector(1, 1, 0) t = view_transform(_from, to, up) assert t == Matrix([[-0.50709, 0.50709, 0.67612, -2.36643], [0.76772, 0.60609, 0.12122, -2.82843], [-0.35857, 0.59761, -0.71714, 0.0], [0.0, 0.0, 0.0, 1.0]])
def test_precomputing_state_of_intersection(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) shape = Sphere() i = Intersection(4, shape) comps = i.prepare_computations(r) 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)
def test_individual_transformations_in_sequence(self): p = Point(1, 0, 1) a = rotation_x(math.pi / 2) b = scaling(5, 5, 5) c = translation(10, 5, 7) p2 = a * p assert p2 == Point(1, -1, 0) p3 = b * p2 assert p3 == Point(5, -5, 0) p4 = c * p3 assert p4 == Point(15, 0, 7)
def test_shade_hit_is_given_an_intersection_in_shadow(self): w = World() w.light_source = PointLight(Point(0, 0, -10), Color.white()) s1 = Sphere() s2 = Sphere() s2.transformation = translation(0, 0, 10) w.add(s1, s2) r = Ray(Point(0, 0, 5), Vector(0, 0, 1)) i = Intersection(4, s2) comps = i.prepare_computations(r) c = w.shade_hit(comps) assert c == Color(0.1, 0.1, 0.1)
def test_lighting_with_pattern_applied(self): m = Material() m.pattern = StripePattern(Color.white(), Color.black()) m.ambient = 1 m.diffuse = 0 m.specular = 0 eyev = Vector(0, 0, -1) normalv = Vector(0, 0, -1) light = PointLight(Point(0, 0, -10), Color.white()) c1 = m.lighting(Sphere(), light, Point(0.9, 0, 0), eyev, normalv, False) c2 = m.lighting(Sphere(), light, Point(1.1, 0, 0), eyev, normalv, False) assert c1 == Color.white() assert c2 == Color.black()
def test_color_at_with_mutually_reflective_surfaces(self): w = World() w.light_source = PointLight(Point(0, 0, 0), Color.white()) lower = Plane() lower.material.reflective = 1 lower.transformation = translation(0, -1, 0) upper = Plane() upper.material.reflective = 1 upper.transformation = translation(0, 1, 0) w.add(lower, upper) r = Ray(Point(0, 0, 0), Vector(0, 1, 0)) # Avoid Infinite Recursion w.color_at(r) assert True
def test_pattern_with_both_object_and_pattern_transformation(self): obj = Sphere() obj.transformation = scaling(2, 2, 2) pattern = test_pattern() pattern.transformation = translation(0.5, 1, 1.5) c = pattern.pattern_at_shape(obj, Point(2.5, 3, 3.5)) assert c == Color(0.75, 0.5, 0.25)
def test_lighting_with_surface_in_shadow(self, background): eyev = Vector(0, 0, -1) normalv = Vector(0, 0, -1) light = PointLight(Point(0, 0, -10), Color(1, 1, 1)) in_shadow = True result = background['m'].lighting(Sphere(), light, background['position'], eyev, normalv, in_shadow) assert result == Color(0.1, 0.1, 0.1)
def test_shading_intersection(self, default_world): w = default_world r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) shape = w.objects[0] i = Intersection(4, shape) comps = i.prepare_computations(r) c = w.shade_hit(comps) assert c == Color(0.38066, 0.47583, 0.2855)
def test_schlick_approximation_with_perpendicular_viewing_angle( self, glass_sphere): shape = glass_sphere() r = Ray(Point(0, 0, 0), Vector(0, 1, 0)) xs = Intersections(Intersection(-1, shape), Intersection(1, shape)) comps = xs[1].prepare_computations(r, xs) reflectance = comps.schlick() assert reflectance == pytest.approx(0.04)
def test_refracted_color_with_opaque_surface(self, default_world): 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)) comps = xs[0].prepare_computations(r, xs) c = w.refracted_color(comps, 5) assert c == Color.black()
def test_schlick_approximation_with_small_angle_and_n2_greater_than_n1( self, glass_sphere): shape = glass_sphere() r = Ray(Point(0, 0.99, -2), Vector(0, 0, 1)) xs = Intersections(Intersection(1.8589, shape)) comps = xs[0].prepare_computations(r, xs) reflectance = comps.schlick() assert reflectance == pytest.approx(0.48873, EPSILON)
def test_hit_should_offset_the_point(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) shape = Sphere() shape.transformation = translation(0, 0, 1) i = Intersection(5, shape) comps = i.prepare_computations(r) assert comps.over_point.z < -EPSILON / 2 assert comps.point.z > comps.over_point.z
def test_schlick_approximation_under_total_internal_reflection( self, glass_sphere): 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)) comps = xs[1].prepare_computations(r, xs) reflectance = comps.schlick() assert reflectance == 1.0
def test_reflected_color_for_nonreflective_material(self, default_world): w = default_world r = Ray(Point(0, 0, 0), Vector(0, 0, 1)) shape = w.objects[1] shape.material.ambient = 1 i = Intersection(1, shape) comps = i.prepare_computations(r) color = w.reflected_color(comps) assert color == Color.black()
def test_intersect_world_with_ray(self, default_world): w = default_world r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) xs = w.intersect(r) assert xs.count == 4 assert xs[0].t == 4 assert xs[1].t == 4.5 assert xs[2].t == 5.5 assert xs[3].t == 6
def test_under_point_is_offset_below_the_surface(self, glass_sphere): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) shape = glass_sphere() shape.transformation = translation(0, 0, 1) i = Intersection(5, shape) xs = Intersections(i) comps = i.prepare_computations(r, xs) assert comps.under_point.z > EPSILON / 2 assert comps.point.z < comps.under_point.z
def test_color_with_intersection_behind_ray(self, default_world): w = default_world outer = w.objects[0] outer.material.ambient = 1 inner = w.objects[1] inner.material.ambient = 1 r = Ray(Point(0, 0, 0.75), Vector(0, 0, -1)) c = w.color_at(r) assert c == inner.material.color
def test_refracted_color_at_max_recursive_depth(self, default_world): 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)) comps = xs[0].prepare_computations(r, xs) c = w.refracted_color(comps, 0) assert c == Color.black()
def test_shade_hit_with_reflective_material(self, default_world): w = default_world shape = Plane() shape.material.reflective = 0.5 shape.transformation = translation(0, -1, 0) w.add(shape) r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2)) i = Intersection(sqrt(2), shape) comps = i.prepare_computations(r) color = w.shade_hit(comps) assert color == Color(0.87676, 0.92434, 0.82917)
def test_reflected_color_for_reflective_material(self, default_world): w = default_world shape = Plane() shape.material.reflective = 0.5 shape.transformation = translation(0, -1, 0) w.add(shape) r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2)) i = Intersection(sqrt(2), shape) comps = i.prepare_computations(r) color = w.reflected_color(comps) assert color == Color(0.19033, 0.23791, 0.14274)
def default_world(): w = World() w.light_source = PointLight(Point(-10, 10, -10), Color.white()) s1 = Sphere() s1.material.color = Color(0.8, 1.0, 0.6) s1.material.diffuse = 0.7 s1.material.specular = 0.2 s2 = Sphere() s2.transformation = scaling(0.5, 0.5, 0.5) w.add(s1, s2) return w
def test_reflected_color_at_max_recursive_depth(self, default_world): w = default_world shape = Plane() shape.material.reflective = 0.5 shape.transformation = translation(0, -1, 0) w.add(shape) r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2)) i = Intersection(sqrt(2), shape) comps = i.prepare_computations(r) color = w.reflected_color(comps, 0) assert color == Color.black()
def test_refracted_color_under_total_internal_reflection(self, default_world): 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)) # 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) assert c == Color.black()
def test_stripe_pattern_alternates_in_x(self): pattern = StripePattern(Color.white(), Color.black()) assert pattern.pattern_at(Point(0, 0, 0)) == Color.white() assert pattern.pattern_at(Point(0.9, 0, 0)) == Color.white() assert pattern.pattern_at(Point(1, 0, 0)) == Color.black() assert pattern.pattern_at(Point(-0.1, 0, 0)) == Color.black() assert pattern.pattern_at(Point(-1, 0, 0)) == Color.black() assert pattern.pattern_at(Point(-1.1, 0, 0)) == Color.white()