開発環境
- macOS Mojave - Apple (OS)
- Emacs (Text Editor)
- Windows 10 Pro (OS)
- Visual Studio Code (Text Editor)
- Python 3.7 (プログラミング言語)
- GIMP (ビットマップ画像編集・加工ソフトウェア、PPM形式(portable pixmap)の画像用)
The Ray Tracer Challenge: A Test-Driven Guide to Your First 3D Renderer (Jamis Buck(著)、Pragmatic Bookshelf)、Chapter 6(Light and Shading)のPut It Together(89)を取り組んでみる。
コード
Python 3
tuples_test.py
#!/usr/bin/env python3 from unittest import TestCase, main from tuples import Tuple, Point, Vector, Color import math class TupleTest(TestCase): def setUp(self): pass def tearDown(self): pass def test_is_point(self): a = Point(4.3, -4.2, 3.1) self.assertEqual(a.x, 4.3) self.assertEqual(a.y, -4.2) self.assertEqual(a.z, 3.1) self.assertEqual(type(a), Point) self.assertNotEqual(type(a), Vector) def test_add(self): a1 = Tuple(3, -2, 5, 1) a2 = Tuple(-2, 3, 1, 0) self.assertEqual(a1 + a2, Tuple(1, 1, 6, 1)) def test_sub(self): p1 = Point(3, 2, 1) p2 = Point(5, 6, 7) self.assertEqual(p1 - p2, Vector(-2, -4, -6)) self.assertEqual(type(p1 - p2), Vector) def test_sub_vector_from_point(self): p = Point(3, 2, 1) v = Vector(5, 6, 7) self.assertEqual(p - v, Point(-2, -4, -6)) def test_sub_vector(self): v1 = Vector(3, 2, 1) v2 = Vector(5, 6, 7) self.assertEqual(v1 - v2, Vector(-2, -4, -6)) def test_sub_vect_from_zero_vect(self): zero = Vector(0, 0, 0) v = Vector(1, -2, 3) self.assertEqual(zero - v, Vector(-1, 2, -3)) def test_neg(self): a = Tuple(1, -2, 3, -4) self.assertEqual(-a, Tuple(-1, 2, -3, 4)) def test_scalar_mul(self): a = Tuple(1, -2, 3, -4) self.assertEqual(a * 3.5, Tuple(3.5, -7, 10.5, -14)) self.assertEqual(a * 0.5, Tuple(0.5, -1, 1.5, -2)) def test_div(self): a = Tuple(1, -2, 3, -4) self.assertEqual(a / 2, Tuple(0.5, -1, 1.5, -2)) def test_mag_vector(self): vectors = [Vector(1, 0, 0), Vector(0, 1, 0), Vector(0, 0, 1), Vector(1, 2, 3), Vector(-1, -2, -3)] mags = [1, 1, 1, math.sqrt(14), math.sqrt(14)] for vector, mag in zip(vectors, mags): self.assertEqual(vector.magnitude(), mag) def test_normalizing_vector(self): v = Vector(4, 0, 0) self.assertEqual(v.normalize(), Vector(1, 0, 0)) v = Vector(1, 2, 3) self.assertEqual(v.normalize(), Vector(1 / math.sqrt(14), 2 / math.sqrt(14), 3 / math.sqrt(14))) norm = v.normalize() self.assertEqual(norm.magnitude(), 1) def test_dot_product(self): a = Vector(1, 2, 3) b = Vector(2, 3, 4) self.assertEqual(a.dot(b), 20) def test_cross_product(self): a = Vector(1, 2, 3) b = Vector(2, 3, 4) self.assertEqual(a.cross(b), Vector(-1, 2, - 1)) self.assertEqual(b.cross(a), Vector(1, -2, 1)) def test_color(self): c = Color(-0.5, 0.4, 1.7) tests = {c.red: -0.5, c.green: 0.4, c.blue: 1.7} for k, v in tests.items(): self.assertEqual(k, v) def test_colors_add(self): c1 = Color(0.9, 0.6, 0.75) c2 = Color(0.7, 0.1, 0.25) self.assertEqual(c1 + c2, Color(1.6, 0.7, 1.0)) def test_colors_sub(self): c1 = Color(0.9, 0.6, 0.75) c2 = Color(0.7, 0.1, 0.25) self.assertEqual(c1 - c2, Color(0.2, 0.5, 0.5)) def test_colors_mul_by_scalar(self): c = Color(0.2, 0.3, 0.4) self.assertEqual(c * 2, Color(0.4, 0.6, 0.8)) def test_colors_mul(self): c1 = Color(1, 0.2, 0.4) c2 = Color(0.9, 1, 0.1) self.assertEqual(c1 * c2, Color(0.9, 0.2, 0.04)) class VectorTest(TestCase): def setUp(self): pass def tearDown(self): pass def test_reflect(self): v = Vector(1, -1, 0) n = Vector(0, 1, 0) self.assertEqual(v.reflect(n), Vector(1, 1, 0)) def test_reflect_slanted_surface(self): v = Vector(0, -1, 0) n = Vector(1 / math.sqrt(2), 1 / math.sqrt(2), 0) self.assertEqual(v.reflect(n), Vector(1, 0, 0)) if __name__ == '__main__': main()
tuples.py
#!/usr/bin/env python3 import math EPSILON = 0.00001 def is_equal(a: float, b: float): return abs(a - b) < EPSILON class Tuple: def __init__(self, x: float, y: float, z: float, w: float): self.x = x self.y = y self.z = z self.w = w def __eq__(self, other): return is_equal(self.x, other.x) and is_equal(self.y, other.y) and \ is_equal(self.z, other.z) and is_equal(self.w, other.w) def __add__(self, other): return self.__class__(self.x + other.x, self.y + other.y, self.z + other.z, self.w + other.w) def __sub__(self, other): return self.__class__(self.x - other.x, self.y - other.y, self.z - other.z, self.w - other.w) def __neg__(self): return self.__class__(-self.x, -self.y, -self.z, -self.w) def __mul__(self, other: float): return self.__class__(self.x * other, self.y * other, self.z * other, self.w * other) def __truediv__(self, other): return self * (1 / other) def magnitude(self): return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2 + self.w ** 2) def normalize(self): mag = self.magnitude() return self.__class__(self.x, self.y, self.z, self.w) / mag def dot(self, other): return sum([a * b for a, b in zip([self.x, self.y, self.z, self.w], [other.x, other.y, other.z, other.w])]) def __repr__(self): return f'{self.__class__.__name__}({self.x},{self.y},{self.z},{self.w})' class Point(Tuple): def __init__(self, x: float, y: float, z: float, w: float = 1): super().__init__(x, y, z, w) def __sub__(self, other): t = super().__sub__(other) if type(other) == self.__class__: return Vector(t.x, t.y, t.z) elif type(other) == Vector: return t raise TypeError( "unsupported operand type(s) for -: " f"'{type(self)}' and '{type(other)}'") class Vector(Tuple): def __init__(self, x: float, y: float, z: float, w: float = 0): super().__init__(x, y, z, w) def cross(self, other): return self.__class__(self.y * other.z - self.z * other.y, self.z * other.x - self.x * other.z, self.x * other.y - self.y * other.x) def reflect(self, normal): return self - normal * 2 * self.dot(normal) class Color(Tuple): def __init__(self, red: float, green: float, blue: float, w: float = 0): super().__init__(red, green, blue, 0) self.red = red self.green = green self.blue = blue def __mul__(self, other): if type(other) == self.__class__: return self.__class__( self.x * other.x, self.y * other.y, self.z * other.z) return super().__mul__(other)
lights_test.py
#!/usr/bin/env python3 from unittest import TestCase, main from tuples import Point, Color from lights import Light class LightTest(TestCase): def setUp(self): pass def tearDown(self): pass def test_light(self): intensity = Color(1, 1, 1) position = Point(0, 0, 0) light = Light(position, intensity) for a, b in [(light.position, position), (light.intensity, intensity)]: self.assertEqual(a, b) if __name__ == '__main__': main()
lights.py
class Light: def __init__(self, position, intensity): self.position = position self.intensity = intensity
materials_test.py
#!/usr/bin/env python3 from unittest import TestCase, main from materials import Material from tuples import Point, Vector, Color from lights import Light import math class MaterialTest(TestCase): def setUp(self): self.m = Material() self.position = Point(0, 0, 0) def tearDown(self): pass def test_marial(self): m = Material() tests = [(m.color, Color(1, 1, 1)), (m.ambient, 0.1), (m.diffuse, 0.9), (m.specular, 0.9), (m.shininess, 200)] for a, b in tests: self.assertEqual(a, b) def test_lighting_with_eye_between_light_surface(self): eye_vecotr = Vector(0, 0, -1) normal_vector = Vector(0, 0, -1) light = Light(Point(0, 0, -10), Color(1, 1, 1)) result = self.m.lighting( light, self.position, eye_vecotr, normal_vector) self.assertEqual(result, Color(1.9, 1.9, 1.9)) def test_lighting_with_eye_between_light_surface_eye45(self): eye_vector = Vector(0, 1 / math.sqrt(2), -1 / math.sqrt(2)) normal_vector = Vector(0, 0, -1) light = Light(Point(0, 0, -10), Color(1, 1, 1)) self.assertEqual( self.m.lighting(light, self.position, eye_vector, normal_vector), Color(1.0, 1.0, 1.0)) def test_lighting_with_eye_opposite_surface_light45(self): eye_vector = Vector(0, 0, -1) normal_vector = Vector(0, 0, -1) light = Light(Point(0, 10, -10), Color(1, 1, 1)) self.assertEqual( self.m.lighting(light, self.position, eye_vector, normal_vector), Color(0.7364, 0.7364, 0.7364)) def test_lighting_eye_reflection(self): eye_vector = Vector(0, -1 / math.sqrt(2), -1 / math.sqrt(2)) normal_vector = Vector(0, 0, -1) light = Light(Point(0, 10, -10), Color(1, 1, 1)) self.assertEqual( self.m.lighting(light, self.position, eye_vector, normal_vector), Color(1.6364, 1.6364, 1.6364)) def test_lighting_behind_surface(self): eye_vector = Vector(0, 0, -1) normal_vector = Vector(0, 0, -1) light = Light(Point(0, 0, 10), Color(1, 1, 1)) self.assertEqual( self.m.lighting(light, self.position, eye_vector, normal_vector), Color(0.1, 0.1, 0.1)) if __name__ == '__main__': main()
materials.py
from tuples import Color, is_equal class Material: def __init__(self): self.color = Color(1, 1, 1) self.ambient = 0.1 self.diffuse = 0.9 self.specular = 0.9 self.shininess = 200 def __eq__(self, other): if self.color != other.color: return False tests = [(self.ambient, other.ambient), (self.diffuse, other.diffuse), (self.specular, other.specular), (self.shininess, other.shininess)] for a, b in tests: if not is_equal(a, b): return False return True def lighting(self, light, point, eye_vector, normal_vector) -> Color: effective_color = self.color * light.intensity light_vector = (light.position - point).normalize() ambient = effective_color * self.ambient light_dot_normal = light_vector.dot(normal_vector) if light_dot_normal < 0: diffuse = Color(0, 0, 0) specular = Color(0, 0, 0) else: diffuse = effective_color * self.diffuse * light_dot_normal reflect_vector = -light_vector.reflect(normal_vector) reflect_dot_eye = reflect_vector.dot(eye_vector) if reflect_dot_eye <= 0: specular = Color(0, 0, 0) else: factor = reflect_dot_eye ** self.shininess specular = light.intensity * self.specular * factor return ambient + diffuse + specular
spheres_test.py
#!/usr/bin/env python3 from unittest import TestCase, main from tuples import Point, Vector from matrices import Matrix from rays import Ray from spheres import Sphere from transformations import translation, scaling from materials import Material import math class SpheresTest(TestCase): def setUp(self): pass def tearDown(self): pass def test_sphere(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = Sphere() xs = s.intersect(r) for a, b in [(len(xs), 2), (xs[0].obj, s), (xs[1].obj, s)]: self.assertEqual(a, b) def test_intersect(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = Sphere() xs = s.intersect(r) self.assertEqual(len(xs), 2) for i, (a, b) in enumerate(zip(xs, [4, 6])): self.assertEqual(a.t, b) def test_intersect_target(self): r = Ray(Point(0, 1, -5), Vector(0, 0, 1)) s = Sphere() xs = s.intersect(r) self.assertEqual(len(xs), 2) for x in xs: self.assertEqual(x.t, 5) def test_intersect_misses(self): r = Ray(Point(0, 2, -5), Vector(0, 0, 1)) s = Sphere() xs = s.intersect(r) self.assertEqual(len(xs), 0) def test_intersect_inside(self): r = Ray(Point(0, 0, 0), Vector(0, 0, 1)) s = Sphere() xs = s.intersect(r) self.assertEqual(len(xs), 2) for a, b in zip(xs, [-1, 1]): self.assertEqual(a.t, b) def test_intersect_behind(self): r = Ray(Point(0, 0, 5), Vector(0, 0, 1)) s = Sphere() xs = s.intersect(r) for a, b in zip(xs, [-6.0, -4.0]): self.assertEqual(a.t, b) def test_transform(self): self.assertEqual(Sphere().transform, Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])) s = Sphere() t = translation(2, 3, 4) s.transform = t self.assertEqual(s.transform, t) def test_intersect_scaled_with_ray(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = Sphere() s.transform = scaling(2, 2, 2) xs = s.intersect(r) for a, b in [(len(xs), 2), (xs[0].t, 3), (xs[1].t, 7)]: self.assertEqual(a, b) def test_normal_at(self): s = Sphere() tests = [((1, 0, 0), (1, 0, 0)), ((0, 1, 0), (0, 1, 0)), ((0, 0, 1), (0, 0, 1)), ((1 / math.sqrt(3), 1 / math.sqrt(3), 1 / math.sqrt(3)), (1 / math.sqrt(3), 1 / math.sqrt(3), 1 / math.sqrt(3)))] for a, b in tests: self.assertEqual(s.normal_at(Point(*a)), Vector(*b)) def test_normalzed_vector(self): s = Sphere() n = s.normal_at(Point(1 / math.sqrt(3), 1 / math.sqrt(3), 1 / math.sqrt(3))) self.assertEqual(n, n.normalize()) def test_normal_translated(self): s = Sphere() s.transform = translation(0, 1, 0) n = s.normal_at(Point(0, 1.70711, -0.70711)) self.assertEqual(n, Vector(0, 0.70711, -0.70711)) def test_material(self): s = Sphere() m = s.material self.assertEqual(m, Material()) def test_material_assigned(self): s = Sphere() m = Material() m.ambient = 1 s.material = m self.assertEqual(s.material, m) if __name__ == '__main__': main()
spheres.py
from tuples import Point from rays import Ray from intersections import Intersection, Intersections from matrices import Matrix from materials import Material import math identity_matrix = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) class Sphere(): def __init__(self): self.transform = identity_matrix self.material = Material() def intersect(self, ray: Ray) -> Intersections: ray = ray.transform(self.transform.inverse()) 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() return Intersections( *[Intersection((-b + c * math.sqrt(discriminant)) / (2 * a), self) for c in [-1, 1]]) def normal_at(self, world_point: Point) -> Point: object_point = self.transform.inverse() * world_point object_normal = object_point - Point(0, 0, 0) world_normal = self.transform.inverse().transpose() * object_normal world_normal.w = 0 return world_normal.normalize()
casting_rays_sphere.py
#!/usr/bin/env python3 from canvas import Canvas from tuples import Point, Color from rays import Ray from spheres import Sphere from transformations import scaling, rotation_z, shearing from materials import Material from lights import Light import math ray_origin = Point(0, 0, -5) wall_z = 10 wall_size = 7.0 canvas_pixels = 100 pixel_size = wall_size / canvas_pixels half = wall_size / 2 canvas = Canvas(canvas_pixels, canvas_pixels) sphere = Sphere() sphere.material = Material() sphere.material.color = Color(1, 0.2, 1) light_position = Point(-10, 10, -10) light_color = Color(1, 1, 1) light = Light(light_position, light_color) for y in range(canvas_pixels): world_y = half - pixel_size * y for x in range(canvas_pixels): world_x = -half + pixel_size * x position = Point(world_x, world_y, wall_z) ray = Ray(ray_origin, (position - ray_origin).normalize()) xs = sphere.intersect(ray) hit = xs.hit() if hit is not None: point = ray.position(hit.t) normal = hit.obj.normal_at(point) eye = -ray.direction color = hit.obj.material.lighting(light, point, eye, normal) canvas.write_pixel(int(x), int(y), color) with open('casting_rays_sphere.ppm', 'w') as f: canvas.to_ppm(f) transforms = [scaling(1, 0.5, 1), scaling(0.5, 1, 1), rotation_z(math.pi / 4) * scaling(0.5, 1, 1), shearing(1, 0, 0, 0, 0, 0) * scaling(0.5, 1, 1)] colors = [Color(1, 0, 0), Color(0, 1, 0), Color(0, 0, 1), Color(0.5, 0.5, 0)] for i, (transform, color) in enumerate(zip(transforms, colors), 1): canvas = Canvas(canvas_pixels, canvas_pixels) sphere.transform = transform sphere.material.color = color for y in range(canvas_pixels): world_y = half - pixel_size * y for x in range(canvas_pixels): world_x = -half + pixel_size * x position = Point(world_x, world_y, wall_z) ray = Ray(ray_origin, (position - ray_origin).normalize()) hit = xs.hit() xs = sphere.intersect(ray) if hit is not None: point = ray.position(hit.t) normal = hit.obj.normal_at(point) eye = -ray.direction color = hit.obj.material.lighting(light, point, eye, normal) canvas.write_pixel(int(x), int(y), color) with open(f'casting_rays_sphere{i}.ppm', 'w') as f: canvas.to_ppm(f)
入出力結果(cmd(コマンドプロンプト)、Terminal、Bash、Jupyter(IPython))
C:\Users\...>py tuples_test.py .... .................... ---------------------------------------------------------------------- Ran 20 tests in 0.001s OK C:\Users\...>py lights_test.py . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK C:\Users\...>py materials_test.py ...... ---------------------------------------------------------------------- Ran 6 tests in 0.001s OK C:\Users\...>py spheres_test.py ............. ---------------------------------------------------------------------- Ran 13 tests in 0.012s OK C:\Users\...>py casting_rays_sphere.py C:\Users\...>py
1 コメント :
افضل شركة كشف تسربات المياه بالرياض https://sites.google.com/site/alfahedclean/detect-water-leaks-in-riyadh-workers-filipina تعانى الكثير من الهيئات أو الشركات والمنازل للعديد من المشكلات الخطيرة المتعلقه بالتسربات المائية ؛فالتسربات المائية تسبب العديد من المخاطر الهائلة منها انتشار العديد من التصدعات أو التشققات الخطيرة التي تتسبب في تعرض المنازل للانهيارات الخطيرة ؛بالإضافة الى الارتفاع الهائل فى فواتير المياه.
كشف تسربات المياه بدون تكسير بالرياض
أعمال العزل المتخصصة بالرياض ؟
1-القيام بأعمال العزل الصوتى
تتمكن افضل شركة كسف تسربات بالرياض و كشف تسربات المياه بالرياض من القيام بأعمال العزل المختلفه سواء عزل البدرومات أو عزل الخزانات والخرسانات وغيرها من أشكال العزل الأخرى من عزل الأسطح أو العزل الحرارى أيضا ؛ http://visit.news/sharikat-kashf-tusarubat ولأن العزل الصوتى من أهم أنواع العزل التى تحمى الأفراد من التعرض للانزعاج أوالأصوات المرتفعه ؛لذلك يتم الاعتماد على أفضل أدوات العزل الحديثة للتخلص من مشكلات الأصوات المرتفعه .
2-القيام بأعمال عزل الأسطح
http://visit.social/sharikat-kashf-tusarubat
تتمكن كشف تسربات المياه من القيام بأعمال عزل الأسطح للتخلص من مخاطر المياه الناجمة عن الأمطار أو أشعه الشمس التى تؤثر سلبيا على الأسطح وتعرضها للعديد من التلفيات الخطيرة ؛لهذا تعتمد شركة كشف تسربات بالرياض على أفضل أنظمة العزل الحديثة سواء العزل التقليدى أو العزل المقلوبة وغيرها من الأساليب الأخرى التى تساعد على القيام بأعمال العزل وحمايه الأسطح من المزيد من المخاطر .
3-القيام بأعمال العزل الحراري
لحمايه المبانى أو المنشأت من التعرض للحرائق أو المخاطر http://pages.today/sharikat-kashf-tusarubat ؛لابد من الحرص على الاعتماد على أفضل أدوات العزل الحرارى للتخلص من الأثار الناجمه عن تواجد كميات هائله من الأجهزة الكهربية سواء البوتجاز أو الغسالات أو الثلاجات وغيرها من الأجهزة التي تؤدى الى الارتفاع الهائل فى درجات الحرارة فى المكان
فقط تواصل مع شركة كشف تسربات المياه بدون تكسير وحافظ على حائط منزلك من التعرض لأى أعمال كسر أو تلفيات تعرض المكان للتشوهات أو المخاطر الهائله ؛فقط نحن شركة كشف تسربات المياه بالرياض التى تمتلك أفضل الطرق والأساليب الحديثة للكشف عن التسربات المائية http://b.link/sharikat-kashf-tusarubat ؛فقط تواصل معنا عبر أرقامنا ولا تدع خدماتنا وعروضنا وخصوماتنا المميزة تفوتك ؛نحن الأفضل دون منافس .
… اقرأ المزيد
المصدر: شركة كشف تسربات بالرياض
コメントを投稿