def test_a_stripe_pattern_is_constant_in_z(): # Given pattern = StripePattern(WHITE, BLACK) # Then assert pattern.pattern_at(Point(0, 0, 0)) == WHITE assert pattern.pattern_at(Point(0, 0, 1)) == WHITE assert pattern.pattern_at(Point(0, 0, 2)) == WHITE
def test_multiplying_by_the_inverse_of_a_translation_matrix(): # Given transform = translation(5, -3, 2) inv = transform.inverse() p = Point(-3, 4, 5) # Then assert inv * p == Point(-8, 7, 3)
def test_a_gradient_linearly_interpolates_between_colors(): # Given pattern = GradientPattern(WHITE, BLACK) # Then assert pattern.pattern_at(Point(0.25, 0, 0)) == Color(0.75, 0.75, 0.75) assert pattern.pattern_at(Point(0.5, 0, 0)) == Color(0.5, 0.5, 0.5) assert pattern.pattern_at(Point(0.75, 0, 0)) == Color(0.25, 0.25, 0.25)
def test_the_inverse_of_an__x_rotation__rotates_in_the_opposite_direction(): # Given p = Point(0, 1, 0) half_quarter = rotation_x(pi / 4) inv = half_quarter.inverse() # Then assert inv * p == Point(0, sqrt(2) / 2, -sqrt(2) / 2)
def test_the_color_when_a_ray_misses__only_negative_intersection_t(): w = World() w.light = PointLight(Point(-10, 10, -10), Color(1, 1, 1)) w.objects = [Plane()] r = Ray(Point(0, 10, 0), Vector(0, 1, 1).normalize()) c = w.color_at(r) assert c == Color(0, 0, 0)
def test_checkers_should_repeat_in_x(): # Given pattern = CheckersPattern(WHITE, BLACK) # Then assert pattern.pattern_at(Point(0, 0, 0)) == WHITE assert pattern.pattern_at(Point(0.99, 0, 0)) == WHITE assert pattern.pattern_at(Point(1.01, 0, 0)) == BLACK
def test_rotating_a_point_around_the_z_axis(): # Given p = Point(0, 1, 0) half_quarter = rotation_z(pi / 4) full_quarter = rotation_z(pi / 2) # Then assert half_quarter * p == Point(-sqrt(2) / 2, sqrt(2) / 2, 0) assert full_quarter * p == Point(-1, 0, 0)
def test_computing_a_point_from_a_distance(): # Given r = Ray(Point(2, 3, 4), Vector(1, 0, 0)) # Then assert r.position(0) == Point(2, 3, 4) assert r.position(1) == Point(3, 3, 4) assert r.position(-1) == Point(1, 3, 4) assert r.position(2.5) == Point(4.5, 3, 4)
def test_a_ring_should_extend_in_both_x_and_z(): # Given pattern = RingPattern(WHITE, BLACK) # Then assert pattern.pattern_at(Point(0, 0, 0)) == WHITE assert pattern.pattern_at(Point(1, 0, 0)) == BLACK assert pattern.pattern_at(Point(0, 0, 1)) == BLACK # 0.708 = just slightly more than sqrt(2) / 2 assert pattern.pattern_at(Point(0.708, 0, 0.708)) == BLACK
def test_the_transformation_matrix_for_the_default_orientation(): # Given f = Point(0, 0, 0) # from to = Point(0, 0, -1) up = Vector(0, 1, 0) # When t = view_transform(f, to, up) # Then assert t == identity_matrix()
def test_a_view_transformation_matrix_looking_in_positive_z_direction(): # Given f = Point(0, 0, 0) to = Point(0, 0, 1) up = Vector(0, 1, 0) # When t = view_transform(f, to, up) # Then assert t == scaling(-1, 1, -1)
def test_scaling_a_ray(): # Given r = Ray(Point(1, 2, 3), Vector(0, 1, 0)) m = scaling(2, 3, 4) # When r2 = r.transform(m) # Then assert r2.origin == Point(2, 6, 12) assert r2.direction == Vector(0, 3, 0)
def test_translating_a_ray(): # Given r = Ray(Point(1, 2, 3), Vector(0, 1, 0)) m = translation(3, 4, 5) # When r2 = r.transform(m) # Then assert r2.origin == Point(4, 6, 8) assert r2.direction == Vector(0, 1, 0)
def test_the_view_transformation_moves_the_world(): # Given f = Point(0, 0, 8) to = Point(0, 0, 0) up = Vector(0, 1, 0) # When t = view_transform(f, to, up) # Then assert t == translation(0, 0, -8)
def test_intersecting_a_scaled_shape_with_a_ray(): # Given r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = MockShape() # When s.transform = scaling(2, 2, 2) _ = s.intersect(r) # Then assert s.saved_ray.origin == Point(0, 0, -2.5) assert s.saved_ray.direction == Vector(0, 0, 0.5)
def test_intersecting_a_translated_shape_with_a_ray(): # Given r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = MockShape() # When s.transform = translation(5, 0, 0) _ = s.intersect(r) # Then assert s.saved_ray.origin == Point(-5, 0, -5) assert s.saved_ray.direction == Vector(0, 0, 1)
def test_chained_transformations_must_be_applied_in_reverse_order(): # Given p = Point(1, 0, 1) A = rotation_x(pi / 2) B = scaling(5, 5, 5) C = translation(10, 5, 7) # When T = C * B * A # Then assert T * p == Point(15, 0, 7)
def test_the_normal_of_a_plane_is_constant_everywhere(): # Given p = Plane() # When n1 = p.local_normal_at(Point(0, 0, 0)) n2 = p.local_normal_at(Point(10, 0, -10)) n3 = p.local_normal_at(Point(-5, 0, 150)) # Then assert n1 == Vector(0, 1, 0) assert n2 == Vector(0, 1, 0) assert n3 == Vector(0, 1, 0)
def test_an_arbitray_view_transformation(): # Given f = Point(1, 3, 2) to = Point(4, -2, 8) up = Vector(1, 1, 0) # When t = view_transform(f, to, up) # Then 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.00000, 0.00000, 0.00000, 0.00000, 1.00000)
def test_lighting_with_the_eye_between_light_and_surface_eye_offset_45degree(): # Given m = Material() position = Point(0, 0, 0) eyev = Vector(0, sqrt(2) / 2, sqrt(2) / 2) normalv = Vector(0, 0, -1) light = PointLight(Point(0, 0, -10), Color(1, 1, 1)) object = Sphere() # When result = m.lighting(object, light, position, eyev, normalv) # Then assert result == Color(1.0, 1.0, 1.0)
def test_rendering_a_world_with_a_camera(): # Given w = default_world() c = Camera(11, 11, pi / 2) f = Point(0, 0, -5) to = Point(0, 0, 0) up = Vector(0, 1, 0) c.transform = view_transform(f, to, up) # When image = c.render(w) # Then assert image.pixel_at(5, 5) == Color(0.38066, 0.47583, 0.2855)
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)
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)
def test_lighting_with_the_eye_opposite_surface_light_offset_45degree(): # Given m = Material() position = Point(0, 0, 0) eyev = Vector(0, 0, -1) normalv = Vector(0, 0, -1) light = PointLight(Point(0, 10, -10), Color(1, 1, 1)) object = Sphere() # When result = m.lighting(object, light, position, eyev, normalv) # Then assert result == Color(0.7364, 0.7364, 0.7364)
def test_lighting_with_the_eye_in_the_path_of_the_reflection_vector(): # Given m = Material() position = Point(0, 0, 0) eyev = Vector(0, -sqrt(2) / 2, -sqrt(2) / 2) normalv = Vector(0, 0, -1) light = PointLight(Point(0, 10, -10), Color(1, 1, 1)) object = Sphere() # When result = m.lighting(object, light, position, eyev, normalv) # Then assert result == Color(1.6364, 1.6364, 1.6364)
def test_lighting_with_the_light_behind_the_surface(): # Given m = Material() position = Point(0, 0, 0) eyev = Vector(0, 0, -1) normalv = Vector(0, 0, -1) light = PointLight(Point(0, 0, 10), Color(1, 1, 1)) object = Sphere() # When result = m.lighting(object, light, position, eyev, normalv) # Then assert result == Color(0.1, 0.1, 0.1)
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)
def ray_for_pixel(self, px, py): # the offsets from the edge of the canvas to the pixel's center xoffset = (px + 0.5) * self.pixel_size yoffset = (py + 0.5) * self.pixel_size # the untransformed coordinates of the pixel in world space. world_x = self.half_width - xoffset world_y = self.half_height - yoffset pixel = self.transform.inverse() * Point(world_x, world_y, -1) origin = self.transform.inverse() * Point(0, 0, 0) direction = (pixel - origin).normalize() return Ray(origin, direction)
def test_computing_the_normal_vector_on_a_cone(): EXAMPLES = [ # point normal (Point(0, 0, 0), Vector(0, 0, 0)), (Point(1, 1, 1), Vector(1, -sqrt(2), 1)), (Point(-1, -1, 0), Vector(-1, 1, 0)), ] for point, normal in EXAMPLES: # Given shape = Cone() # When n = shape.local_normal_at(point) # Then assert n == normal
def test_converting_a_point_from_world_to_object_space(): # Given g1 = Group() g1.transform = rotation_y(pi / 2) g2 = Group() g2.transform = scaling(2, 2, 2) g1.add_child(g2) s = Sphere() s.transform = translation(5, 0, 0) g2.add_child(s) # When p = s.world_to_object(Point(-2, 0, -10)) # Then assert p == Point(0, 0, -1)