コード例 #1
0
    def lighting(
        self,
        eyev: Vector,
        normalv: Vector,
        point: Point,
        light: PointLight,
        inShadow: bool = False,
    ):
        diffuse = Color(0, 0, 0)
        specular = Color(0, 0, 0)
        effective_color = self.color * light.intensity
        ambient = effective_color * self.ambient
        if inShadow:
            return ambient

        lightv = (light.position - point).normalize()
        light_dot_normal = lightv.dot(normalv)
        if light_dot_normal >= 0:
            diffuse = effective_color * self.diffuse * light_dot_normal
            reflectv = -lightv.reflect(normalv)
            reflect_dot_eye = reflectv.dot(eyev)
            if reflect_dot_eye > 0:
                factor = pow(reflect_dot_eye, self.shininess)
                specular = light.intensity * self.specular * factor

        return ambient + diffuse + specular
コード例 #2
0
 def reflected_color(self, comps, remaining: int = MAXBOUNCE) -> Color:
     if remaining < 1:
         return Color(0, 0, 0)
     if comps.object.material.reflective == 0:
         return Color(0, 0, 0)
     reflect_ray = Ray(comps.over_point, comps.reflectv)
     color = self.color_at(reflect_ray, remaining - 1)
     return color * comps.object.material.reflective
コード例 #3
0
def test_lighting_eye_in_path():  # eye in reflection path
    s = Sphere()
    m = Material()
    p = Point(0, 0, 0)
    eyev = Vector(0, -math.sqrt(2) / 2, -math.sqrt(2) / 2)
    normalv = Vector(0, 0, -1)
    light = PointLight(Point(0, 10, -10), Color(1, 1, 1))
    res = m.lighting(s, light, p, eyev, normalv)
    assert res == Color(1.6364, 1.6364, 1.6364)
コード例 #4
0
def test_lighting_eye_opposite():  # eye opposite surface, 45 offset
    s = Sphere()
    m = Material()
    p = Point(0, 0, 0)
    eyev = Vector(0, 0, -1)
    normalv = Vector(0, 0, -1)
    light = PointLight(Point(0, 10, -10), Color(1, 1, 1))
    res = m.lighting(s, light, p, eyev, normalv)
    assert res == Color(0.7364, 0.7364, 0.7364)
コード例 #5
0
def test_lighting_eye_offset():  # eye between light and surface, 45 offset
    s = Sphere()
    m = Material()
    p = Point(0, 0, 0)
    eyev = Vector(0, math.sqrt(2) / 2, -math.sqrt(2) / 2)
    normalv = Vector(0, 0, -1)
    light = PointLight(Point(0, 0, -10), Color(1, 1, 1))
    res = m.lighting(s, light, p, eyev, normalv)
    assert res == Color(1.0, 1.0, 1.0)
コード例 #6
0
def test_lighting_eye_between():  # eye between light and surface
    s = Sphere()
    m = Material()
    p = Point(0, 0, 0)
    eyev = Vector(0, 0, -1)
    normalv = Vector(0, 0, -1)
    light = PointLight(Point(0, 0, -10), Color(1, 1, 1))
    res = m.lighting(s, light, p, eyev, normalv)
    assert res == Color(1.9, 1.9, 1.9)
コード例 #7
0
def test_lighting_behind_surface():  # eye behind surface
    s = Sphere()
    m = Material()
    p = Point(0, 0, 0)
    eyev = Vector(0, 0, -1)
    normalv = Vector(0, 0, -1)
    light = PointLight(Point(0, 0, 10), Color(1, 1, 1))
    res = m.lighting(s, light, p, eyev, normalv)
    assert res == Color(0.1, 0.1, 0.1)
コード例 #8
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_inside_intersection_shading():
    w = World.default()
    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)
    comps = i.prepare_computation(r)
    c = w.shade_hit(comps)
    assert c == Color(0.90498, 0.90498, 0.90498)
コード例 #9
0
def test_surface_shadow():
    s = Sphere()
    m = Material()
    p = Point(0, 0, 0)
    eyev = Vector(0, 0, -1)
    normalv = Vector(0, 0, -1)
    light = PointLight(Point(0, 0, -10), Color(1, 1, 1))
    in_shadow = True
    result = m.lighting(s, light, p, eyev, normalv, in_shadow)
    assert result == Color(0.1, 0.1, 0.1)
コード例 #10
0
ファイル: test_canvas.py プロジェクト: tobycyanide/pytracer
def test_ppm():
    c = Canvas(5, 3)
    c1 = Color(1.5, 0, 0)
    c2 = Color(0, 0.5, 0)
    c3 = Color(-0.5, 0, 1)
    c.write_pixel(0, 0, c1)
    c.write_pixel(2, 1, c2)
    c.write_pixel(4, 2, c3)
    assert (
        "255 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n0 0 0 0 0 0 0 128 0 0 0 0 0 0 0\n0 0 0 0 0 0 0 0 0 0 0 0 0 0 255"
        in c.to_ppm()
    )
コード例 #11
0
 def default(cls):
     world = cls()
     world.light = PointLight(Point(-10, 10, -10), Color(1, 1, 1))
     m = Material()
     m.color = Color(0.8, 1.0, 0.6)
     m.diffuse = 0.7
     m.specular = 0.2
     s1 = Sphere()
     s1.set_material(m)
     s2 = Sphere()
     s2.set_transform(Scaling(0.5, 0.5, 0.5))
     world.objects.extend([s1, s2])
     return world
コード例 #12
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_shadow_shade_hit():
    w = World()
    w.light = PointLight(Point(0, 0, -10), Color(1, 1, 1))
    s1 = Sphere()
    s2 = Sphere()
    s2.set_transform(Translation(0, 0, 10))
    w.objects.extend([s1, s2])
    r = Ray(Point(0, 0, 5), Vector(0, 0, 1))
    i = Intersection(4, s2)
    comps = i.prepare_computation(r)
    c = w.shade_hit(comps)
    print(c)
    assert c == Color(0.1, 0.1, 0.1)
コード例 #13
0
def test_lighting_pattern():
    s = Sphere()
    m = Material()
    m.pattern = StripePattern(Color(1, 1, 1), Color(0, 0, 0))
    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(1, 1, 1))
    c1 = m.lighting(s, light, Point(0.9, 0, 0), eyev, normalv, False)
    c2 = m.lighting(s, light, Point(1.1, 0, 0), eyev, normalv, False)
    assert c1 == Color(1, 1, 1)
    assert c2 == Color(0, 0, 0)
コード例 #14
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_default_world():
    light = PointLight(Point(-10, 10, -10), Color(1, 1, 1))
    s1 = Sphere()
    m = Material()
    m.color = Color(0.8, 1.0, 0.6)
    m.diffuse = 0.7
    m.specular = 0.2
    s1.set_material(m)
    s2 = Sphere()
    t = Scaling(0.5, 0.5, 0.5)
    s2.set_transform(t)
    w = World.default()
    assert w.light == light
    assert s1 in w.objects
    assert s2 in w.objects
コード例 #15
0
 def color_at(self, ray: Ray, remaining: int = MAXBOUNCE) -> Color:
     xs = self.intersect(ray)
     hit = xs.hit()
     if hit is None:
         return Color(0, 0, 0)
     else:
         return self.shade_hit(hit.prepare_computation(ray, xs), remaining)
コード例 #16
0
def test_default_material():
    m = Material()
    assert m.color == Color(1, 1, 1)
    assert m.ambient == 0.1
    assert m.diffuse == 0.9
    assert m.specular == 0.9
    assert m.shininess == 200
コード例 #17
0
ファイル: test_canvas.py プロジェクト: tobycyanide/pytracer
def test_canvas():
    c = Canvas(10, 20)
    assert c.width == 10
    assert c.height == 20
    for row in c.pixels:
        for pixel in row:
            assert pixel == Color(0, 0, 0)
コード例 #18
0
 def test_pixel_data(self):
     canvas = Canvas(5, 3)
     c1 = Color(1.5, 0, 0)
     c2 = Color(0, 0.5, 0)
     c3 = Color(-0.5, 0, 1)
     canvas.write_pixel(0, 0, c1)
     canvas.write_pixel(2, 1, c2)
     canvas.write_pixel(4, 2, c3)
     ppm = canvas.to_ppm()
     pixel_data = [s.strip() for s in ppm.splitlines()][3:6]
     expected_data = [
         "255 0 0 0 0 0 0 0 0 0 0 0 0 0 0",
         "0 0 0 0 0 0 0 128 0 0 0 0 0 0 0",
         "0 0 0 0 0 0 0 0 0 0 0 0 0 0 255",
     ]
     self.assertEqual(pixel_data, expected_data)
コード例 #19
0
def test_both_transform():
    s = Sphere()
    s.set_transform(Scaling(2, 2, 2))
    pattern = _TestPattern()
    pattern.set_pattern_transform(Translation(0.5, 1, 1.5))
    c = pattern.pattern_at_shape(s, Point(2.5, 3, 3.5))
    assert c == Color(0.75, 0.5, 0.25)
コード例 #20
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def shade_hit_transparent():
    w = World().default()
    floor = Plane()
    floor.set_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.set_transform(Translation(0, -3.5, -0.5))
    w.objects.append(ball)
    r = Ray(Point(0, 0, -3), Vector(0, -math.sqrt(2) / 2, math.sqrt(2) / 2))
    xs = Intersections(Intersection(math.sqrt(2), floor))
    comps = xs[0].prepare_computations(r, xs)
    color = w.shade_hit(comps, 5)
    assert color == Color(0.93642, 0.68642, 0.68642)
コード例 #21
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_intersection_shading():
    w = World.default()
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = w.objects[0]
    i = Intersection(4, shape)
    comps = i.prepare_computation(r)
    c = w.shade_hit(comps)
    assert c == Color(0.38066, 0.47583, 0.2855)
コード例 #22
0
 def test_creation(self):
     canvas = Canvas(10, 20)
     self.assertEqual(canvas.width, 10)
     self.assertEqual(canvas.height, 20)
     black = Color(0, 0, 0)
     for row in canvas.pixels:
         for elem in row:
             self.assertEqual(elem, black)
コード例 #23
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_refracted_opaque():
    w = World().default()
    s = w.objects[0]
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    xs = Intersections(Intersection(4, s), Intersection(6, s))
    comps = xs[0].prepare_computation(r, xs)
    c = w.refracted_color(comps, 5)
    assert c == Color(0, 0, 0)
コード例 #24
0
ファイル: test_camera.py プロジェクト: tobycyanide/pytracer
def test_render():
    w = World.default()
    c = Camera(11, 11, math.pi / 2)
    f = Point(0, 0, -5)
    to = Point(0, 0, 0)
    up = Vector(0, 1, 0)
    c.transform = ViewTransform(f, to, up)
    image = c.render(w)
    assert image.read_pixel(5, 5) == Color(0.38066, 0.47583, 0.2855)
コード例 #25
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_reflected_color_nonreflective():
    w = World().default()
    r = Ray(Point(0, 0, 0), Vector(0, 0, 1))
    s = w.objects[0]
    s.material.ambient = 1
    i = Intersection(1, s)
    comps = i.prepare_computation(r)
    c = w.reflected_color(comps)
    assert c == Color(0, 0, 0)
コード例 #26
0
    def refracted_color(self, comps, remaining: int = MAXBOUNCE) -> Color:
        if remaining < 1:
            return Color(0, 0, 0)
        if comps.object.material.transparency == 0:
            return Color(0, 0, 0)

        n_ratio = comps.n1 / comps.n2
        cos_i = comps.eyev.dot(comps.normalv)
        sin2_t = (n_ratio**2) * (1 - (cos_i**2))
        if sin2_t > 1:
            return Color(0, 0, 0)

        cos_t = math.sqrt(1.0 - sin2_t)
        direction = comps.normalv * (n_ratio * cos_i -
                                     cos_t) - comps.eyev * n_ratio
        refract_ray = Ray(comps.under_point, direction)
        color = (self.color_at(refract_ray, remaining - 1) *
                 comps.object.material.transparency)
        return color
コード例 #27
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_refracted_max_depth():
    w = World().default()
    s = w.objects[0]
    s.material.transparency = 1.0
    s.material.refractive_index = 1.5
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    xs = Intersections(Intersection(4, s), Intersection(6, s))
    comps = xs[0].prepare_computation(r, xs)
    c = w.refracted_color(comps, 0)
    assert c == Color(0, 0, 0)
コード例 #28
0
 def test_line_length(self):
     canvas = Canvas(10, 2, Color(1, 0.8, 0.6))
     ppm = canvas.to_ppm()
     pixel_data = [s.strip() for s in ppm.splitlines()][3:7]
     expected_data = [
         "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204",
         "153 255 204 153 255 204 153 255 204 153 255 204 153",
         "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204",
         "153 255 204 153 255 204 153 255 204 153 255 204 153",
     ]
     self.assertEqual(pixel_data, expected_data)
コード例 #29
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_shade_hit_reflective():
    w = World().default()
    s = Plane()
    s.material.reflective = 0.5
    s.set_transform(Translation(0, -1, 0))
    w.objects.append(s)
    r = Ray(Point(0, 0, -3), Vector(0, -math.sqrt(2) / 2, math.sqrt(2) / 2))
    i = Intersection(math.sqrt(2), s)
    comps = i.prepare_computation(r)
    c = w.shade_hit(comps)
    assert c == Color(0.87677, 0.92436, 0.82918)
コード例 #30
0
ファイル: test_world.py プロジェクト: tobycyanide/pytracer
def test_maximum_recursion_depth_color_at():
    w = World().default()
    s = Plane()
    s.material.reflective = 0.5
    s.set_transform(Translation(0, -1, 0))
    w.objects.append(s)
    r = Ray(Point(0, 0, -3), Vector(0, -math.sqrt(2) / 2, math.sqrt(2) / 2))
    i = Intersection(math.sqrt(2), s)
    comps = i.prepare_computation(r)
    color = w.reflected_color(comps, 0)
    assert color == Color(0, 0, 0)