def main() -> None: aspect_ratio = 16 / 9 image_width = 720 image_height = int(image_width / aspect_ratio) samples_per_pixel = 48 max_depth = 5 world = random_scene() lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus = 10 aperture = 0.1 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus) print("Start rendering.") start_time = time.time() img_list = Parallel(n_jobs=2, verbose=20)( delayed(scan_frame)(world, cam, image_width, image_height, max_depth) for s in range(samples_per_pixel)) end_time = time.time() print(f"\nDone. Total time: {round(end_time - start_time, 1)} s.") final_img = Img(image_width, image_height) for img in img_list: final_img.write_frame(img) final_img.average(samples_per_pixel).gamma(2) final_img.save("./output.png", True)
def main() -> None: aspect_ratio = 16 / 9 image_width = 256 image_height = int(image_width / aspect_ratio) samples_per_pixel = 20 max_depth = 10 world: HittableList = three_ball_scene() lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0.1 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus) print("Start rendering.") start_time = time.time() n_processer = multiprocessing.cpu_count() img_list: List[Img] = Parallel(n_jobs=n_processer)( delayed(scan_line)(j, world, cam, image_width, image_height, samples_per_pixel, max_depth) for j in range(image_height - 1, -1, -1)) final_img = Img(image_width, image_height) final_img.set_array(np.concatenate([img.frame for img in img_list])) end_time = time.time() print(f"\nDone. Total time: {round(end_time - start_time, 1)} s.") final_img.save("./output.png", True)
def __init__(self, obj: Hittable, angle: float) -> None: radians = degrees_to_radians(angle) self.sin_theta = np.sin(radians) self.cos_theta = np.cos(radians) self.obj = obj self.bbox = obj.bounding_box(0, 1) if self.bbox is None: raise ValueError point_min = Point3(np.inf, np.inf, np.inf) point_max = Point3(-np.inf, -np.inf, -np.inf) for i in range(2): for j in range(2): for k in range(2): x = i * self.bbox.max().x() + (1 - i) * self.bbox.min().x() y = j * self.bbox.max().y() + (1 - j) * self.bbox.min().y() z = k * self.bbox.max().z() + (1 - k) * self.bbox.min().z() newx = self.cos_theta * x + self.sin_theta * z newz = -self.sin_theta * x + self.cos_theta * z new = Vec3(newx, y, newz) for c in range(3): point_min[c] = np.minimum(point_min[c], new[c]) point_max[c] = np.maximum(point_max[c], new[c]) self.bbox = AABB(point_min, point_max)
def main() -> None: aspect_ratio = 16 / 9 image_width = 256 image_height = int(image_width / aspect_ratio) samples_per_pixel = 20 max_depth = 10 world: HittableList = three_ball_scene() lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0.1 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus) print("Start rendering.") start_time = time.time() n_processer = multiprocessing.cpu_count() img_list: List[Img] = Parallel(n_jobs=n_processer, verbose=10)( delayed(scan_line)(j, world, cam, image_width, image_height, samples_per_pixel, max_depth) for j in range(image_height - 1, -1, -1)) # # Profile prologue # import cProfile # import pstats # import io # from pstats import SortKey # pr = cProfile.Profile() # pr.enable() # img_list: List[Img] = list() # for j in range(image_height-1, -1, -1): # img_list.append( # scan_line( # j, world, cam, # image_width, image_height, # samples_per_pixel, max_depth # ) # ) # # Profile epilogue # pr.disable() # s = io.StringIO() # sortby = SortKey.CUMULATIVE # ps = pstats.Stats(pr, stream=s).sort_stats(sortby) # ps.print_stats() # print(s.getvalue()) final_img = Img(image_width, image_height) final_img.set_array(np.concatenate([img.frame for img in img_list])) end_time = time.time() print(f"\nDone. Total time: {round(end_time - start_time, 1)} s.") final_img.save("./output.png", True)
def three_ball_scene() -> HittableList: world = HittableList() world.add(Sphere(Point3(0, 0, -1), 0.5, Lambertian(Color(0.1, 0.2, 0.5)))) world.add( Sphere(Point3(0, -100.5, -1), 100, Lambertian(Color(0.8, 0.8, 0)))) world.add(Sphere(Point3(1, 0, -1), 0.5, Metal(Color(0.8, 0.6, 0.2), 0.3))) world.add(Sphere(Point3(-1, 0, -1), 0.5, Dielectric(1.5))) world.add(Sphere(Point3(-1, 0, -1), -0.45, Dielectric(1.5))) return world
def main() -> None: aspect_ratio = 16 / 9 image_width = 1920 image_height = int(image_width / aspect_ratio) samples_per_pixel = 48 max_depth = 10 world: HittableList = random_scene() lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0.1 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus) print("Start rendering.") start_time = time.time() img_list: List[Vec3List] = Parallel(n_jobs=4, verbose=20)( delayed(scan_frame)(world, cam, image_width, image_height, max_depth) for s in range(samples_per_pixel)) # # Profile prologue # import cProfile # import pstats # import io # from pstats import SortKey # pr = cProfile.Profile() # pr.enable() # img_list: List[Vec3List] = list() # for sample_num in range(samples_per_pixel): # img_list.append( # scan_frame(world, cam, image_width, image_height, max_depth) # ) # # Profile epilogue # pr.disable() # s = io.StringIO() # sortby = SortKey.CUMULATIVE # ps = pstats.Stats(pr, stream=s).sort_stats(sortby) # ps.print_stats() # print(s.getvalue()) end_time = time.time() print(f"\nDone. Total time: {round(end_time - start_time, 1)} s.") final_img = Img(image_width, image_height) for img in img_list: final_img.write_frame(img) final_img.average(samples_per_pixel).gamma(2).up_side_down() final_img.save("./output.png", True)
def surrounding_box(box0: AABB, box1: AABB) -> AABB: small = Point3(min(box0.min().x(), box1.min().x()), min(box0.min().y(), box1.min().y()), min(box0.min().z(), box1.min().z())) big = Point3(max(box0.max().x(), box1.max().x()), max(box0.max().y(), box1.max().y()), max(box0.max().z(), box1.max().z())) return AABB(small, big)
def three_ball_scene(): world = HittableList() world.add( Sphere(Point3(0, 0, -1), 0.5, Lambertian(Color(0.1, 0.2, 0.5), 1))) world.add( Sphere(Point3(0, -100.5, -1), 100, Lambertian(Color(0.8, 0.8, 0), 2))) world.add( Sphere(Point3(1, 0, -1), 0.5, Metal(Color(0.8, 0.6, 0.2), 0.3, 3))) material_dielectric = Dielectric(1.5, 4) world.add(Sphere(Point3(-1, 0, -1), 0.5, material_dielectric)) world.add(Sphere(Point3(-1, 0, -1), -0.45, material_dielectric)) return world
def __init__(self, origin: Point3 = Point3(), direction: Vec3 = Vec3(), time: float = 0) -> None: self.orig = origin self.dir = direction self.tm = time
def three_ball_scene(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() world.add( Sphere(Point3(0, 0, -1), 0.5, Lambertian(SolidColor(0.1, 0.2, 0.5)))) world.add( Sphere(Point3(0, -100.5, -1), 100, Lambertian(SolidColor(0.8, 0.8, 0)))) world.add(Sphere(Point3(1, 0, -1), 0.5, Metal(Color(0.8, 0.6, 0.2), 0.3))) world.add(Sphere(Point3(-1, 0, -1), 0.5, Dielectric(1.5))) world.add(Sphere(Point3(-1, 0, -1), -0.45, Dielectric(1.5))) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(3, 3, 2) lookat = Point3(0, 0, -1) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = (lookfrom - lookat).length() aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) # lookfrom = Point3(13, 2, 3) # lookat = Point3(0, 0, 0) # vup = Vec3(0, 1, 0) # vfov = 20 # dist_to_focus: float = 10 # aperture: float = 0.1 # cam = Camera( # lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, # time0, time1 # ) return world_bvh, cam
def two_perlin_spheres(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() pertext = NoiseTexture(4) world.add(Sphere(Point3(0, -1000, 0), 1000, Lambertian(pertext))) world.add(Sphere(Point3(0, 2, 0), 2, Lambertian(pertext))) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam
def turb(self, p: Point3, depth: int = 7) -> float: accum: float = 0 weight: float = 1 temp_p = p.copy() for i in range(depth): accum += weight * self.noise(temp_p) weight *= 0.5 temp_p *= 2 return np.abs(accum)
def random_scene(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() # ground_material = Lambertian(SolidColor(0.5, 0.5, 0.5)) ground_material = Lambertian( CheckerTexture(SolidColor(0.2, 0.3, 0.1), SolidColor(0.9, 0.9, 0.9))) world.add(Sphere(Point3(0, -1000, 0), 1000, ground_material)) for a in range(-11, 11): for b in range(-11, 11): choose_mat = random_float() center = Point3(a + 0.9 * random_float(), 0.2, b + 0.9 * random_float()) if (center - Vec3(4, 0.2, 0)).length() > 0.9: if choose_mat < 0.6: # Diffuse albedo = Color.random() * Color.random() sphere_material_diffuse = Lambertian(SolidColor(albedo)) center2 = center + Vec3(0, random_float(0, 0.5), 0) world.add( MovingSphere(center, center2, 0, 1, 0.2, sphere_material_diffuse)) elif choose_mat < 0.8: # Metal albedo = Color.random(0.5, 1) fuzz = random_float(0, 0.5) sphere_material_metal = Metal(albedo, fuzz) world.add(Sphere(center, 0.2, sphere_material_metal)) else: # Glass sphere_material_glass = Dielectric(1.5) world.add(Sphere(center, 0.2, sphere_material_glass)) material_1 = Dielectric(1.5) world.add(Sphere(Point3(0, 1, 0), 1, material_1)) material_2 = Lambertian(SolidColor(0.4, 0.2, 0.1)) world.add(Sphere(Point3(-4, 1, 0), 1, material_2)) material_3 = Metal(Color(0.7, 0.6, 0.5), 0) world.add(Sphere(Point3(4, 1, 0), 1, material_3)) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0.1 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam
def two_spheres(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() checker = CheckerTexture(SolidColor(0.2, 0.3, 0.1), SolidColor(0.9, 0.9, 0.9)) world.add(Sphere(Point3(0, -10, 0), 10, Lambertian(checker))) world.add(Sphere(Point3(0, 10, 0), 10, Lambertian(checker))) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(13, 2, 3) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam
def earth(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() earth_texture = ImageTexture("earthmap.jpg") earth_surface = Lambertian(earth_texture) globe = Sphere(Point3(0, 0, 0), 2, earth_surface) world.add(globe) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(0, 0, -5) lookat = Point3(0, 0, 0) vup = Vec3(0, 1, 0) vfov = 50 dist_to_focus: float = 10 aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam
def random_scene() -> HittableList: world = HittableList() ground_material = Lambertian(Color(0.5, 0.5, 0.5), 1) world.add(Sphere(Point3(0, -1000, 0), 1000, ground_material)) sphere_material_glass = Dielectric(1.5, 2) for a in range(-11, 11): for b in range(-11, 11): choose_mat = random_float() center = Point3(a + 0.9 * random_float(), 0.2, b + 0.9 * random_float()) if (center - Vec3(4, 0.2, 0)).length() > 0.9: idx = (a * 22 + b) + (11 * 22 + 11) + 6 if choose_mat < 0.6: # Diffuse albedo = Color.random() * Color.random() sphere_material_diffuse = Lambertian(albedo, idx) world.add(Sphere(center, 0.2, sphere_material_diffuse)) elif choose_mat < 0.8: # Metal albedo = Color.random(0.5, 1) fuzz = random_float(0, 0.5) sphere_material_metal = Metal(albedo, fuzz, idx) world.add(Sphere(center, 0.2, sphere_material_metal)) else: # Glass world.add(Sphere(center, 0.2, sphere_material_glass)) material_1 = Dielectric(1.5, 3) world.add(Sphere(Point3(0, 1, 0), 1, material_1)) material_2 = Lambertian(Color(0.4, 0.2, 0.1), 4) world.add(Sphere(Point3(-4, 1, 0), 1, material_2)) material_3 = Metal(Color(0.7, 0.6, 0.5), 0, 5) world.add(Sphere(Point3(4, 1, 0), 1, material_3)) return world
def noise(self, p: Point3) -> float: u = p.x() - np.floor(p.x()) v = p.y() - np.floor(p.y()) w = p.z() - np.floor(p.z()) i = int(np.floor(p.x())) j = int(np.floor(p.y())) k = int(np.floor(p.z())) c: List[List[List[Vec3]]] = np.empty((2, 2, 2), dtype=object) for di in range(2): for dj in range(2): for dk in range(2): c[di][dj][dk] = self.ranvec[self.perm_x[(i + di) & 255] ^ self.perm_y[(j + dj) & 255] ^ self.perm_z[(k + dk) & 255]] return Perlin.trilinear_interp(c, u, v, w)
def simple_light(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() pertext = NoiseTexture(4) world.add(Sphere(Point3(0, -1000, 0), 1000, Lambertian(pertext))) world.add(Sphere(Point3(0, 2, 0), 2, Lambertian(pertext))) difflight = DiffuseLight(SolidColor(4, 4, 4)) world.add(Sphere(Point3(0, 7, 0), 2, difflight)) world.add(XYRect(3, 5, 1, 3, -2, difflight)) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(23, 4, 5) lookat = Point3(0, 2, 0) vup = Vec3(0, 1, 0) vfov = 20 dist_to_focus: float = 10 aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam
def cornell_box(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() # Colors red = Lambertian(SolidColor(0.65, 0.05, 0.05)) white = Lambertian(SolidColor(0.73, 0.73, 0.73)) green = Lambertian(SolidColor(0.12, 0.45, 0.15)) light = DiffuseLight(SolidColor(15, 15, 15)) # Outer box world.add(FlipFace(YZRect(0, 555, 0, 555, 555, green))) world.add(YZRect(0, 555, 0, 555, 0, red)) world.add(XZRect(213, 343, 227, 332, 554, light)) world.add(XZRect(0, 555, 0, 555, 0, white)) world.add(FlipFace(XZRect(0, 555, 0, 555, 555, white))) world.add(FlipFace(XYRect(0, 555, 0, 555, 555, white))) # Objects in the box box1: Hittable = Box(Vec3(0, 0, 0), Point3(165, 330, 165), white) box1 = RotateY(box1, 15) box1 = Translate(box1, Point3(265, 0, 295)) box1 = ConstantMedium(box1, 0.01, SolidColor(0, 0, 0)) world.add(box1) box2: Hittable = Box(Point3(0, 0, 0), Point3(165, 165, 165), white) box2 = RotateY(box2, -18) box2 = Translate(box2, Point3(130, 0, 65)) box2 = ConstantMedium(box2, 0.01, SolidColor(1, 1, 1)) world.add(box2) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(278, 278, -800) lookat = Point3(278, 278, 0) vup = Vec3(0, 1, 0) vfov = 40 dist_to_focus: float = 10 aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam
def __init__( self, _min: Point3 = Point3(), _max: Point3 = Point3()) -> None: self._min = _min self._max = _max
def bounding_box(self, t0: float, t1: float) -> Optional[AABB]: output_box = AABB( Point3(self.k-0.0001, self.y0, self.z0), Point3(self.k+0.0001, self.y1, self.z1) ) return output_box
def __init__( self, origin: Point3 = Point3(), direction: Vec3 = Vec3()) -> None: self.orig = origin self.dir = direction
def __init__(self, origin = Point3(), direction = Vec3()): self.o = origin self.d = direction
def __init__(self, p0: Point3, p1: Point3, mat: Material) -> None: self.box_min = p0 self.box_max = p1 self.sides = HittableList() self.sides.add(XYRect(p0.x(), p1.x(), p0.y(), p1.y(), p1.z(), mat)) self.sides.add( FlipFace(XYRect(p0.x(), p1.x(), p0.y(), p1.y(), p0.z(), mat))) self.sides.add(XZRect(p0.x(), p1.x(), p0.z(), p1.z(), p1.y(), mat)) self.sides.add( FlipFace(XZRect(p0.x(), p1.x(), p0.z(), p1.z(), p0.y(), mat))) self.sides.add(YZRect(p0.y(), p1.y(), p0.z(), p1.z(), p1.x(), mat)) self.sides.add( FlipFace(YZRect(p0.y(), p1.y(), p0.z(), p1.z(), p0.x(), mat)))
def value(self, u: float, v: float, p: Point3) -> Color: # return Color(1, 1, 1) * 0.5 * (1 + self.noise.noise(self.scale * p)) # return Color(1, 1, 1) * self.noise.turb(self.scale * p) return (Color(1, 1, 1) * 0.5 * (1 + np.sin(self.scale * p.z() + 10 * self.noise.turb(p))))
def value(self, u: float, v: float, p: Point3) -> Color: sines = np.sin(10 * p.x()) * np.sin(10 * p.y()) * np.sin(10 * p.z()) if sines < 0: return self.odd.value(u, v, p) else: return self.even.value(u, v, p)
def final_scene(aspect_ratio: float, time0: float, time1: float) \ -> Tuple[BVHNode, Camera]: world = HittableList() # Ground boxes1 = HittableList() ground = Lambertian(SolidColor(0.48, 0.83, 0.53)) boxes_per_side = 20 for i in range(boxes_per_side): for j in range(boxes_per_side): w = 100 x0 = -1000 + i * w z0 = -1000 + j * w y0 = 0 x1 = x0 + w y1 = random_float(1, 101) z1 = z0 + w boxes1.add(Box(Point3(x0, y0, x0), Point3(x1, y1, z1), ground)) world.add(BVHNode(boxes1.objects, time0, time1)) # Light light = DiffuseLight(SolidColor(7, 7, 7)) world.add(XZRect(123, 423, 147, 412, 554, light)) # Moving sphere center1 = Point3(400, 400, 200) center2 = center1 + Vec3(30, 0, 0) moving_sphere_material = Lambertian(SolidColor(0.7, 0.3, 0.1)) world.add(MovingSphere(center1, center2, 0, 1, 50, moving_sphere_material)) # Dielectric & metal balls world.add(Sphere(Point3(260, 150, 45), 50, Dielectric(1.5))) world.add( Sphere(Point3(0, 150, 145), 50, Metal(Color(0.8, 0.8, 0.9), 10.0))) # The subsurface reflection sphere boundary = Sphere(Point3(360, 150, 145), 70, Dielectric(1.5)) world.add(boundary) world.add(ConstantMedium(boundary, 0.2, SolidColor(0.2, 0.4, 0.9))) # Big thin mist mist = Sphere(Point3(0, 0, 0), 5000, Dielectric(1.5)) world.add(ConstantMedium(mist, 0.0001, SolidColor(1, 1, 1))) # Earth and marble ball emat = Lambertian(ImageTexture("earthmap.jpg")) world.add(Sphere(Point3(400, 200, 400), 100, emat)) pertext = NoiseTexture(0.1) world.add(Sphere(Point3(220, 280, 300), 80, Lambertian(pertext))) # Foam boxes2 = HittableList() white = Lambertian(SolidColor(0.73, 0.73, 0.73)) ns = 1000 for j in range(ns): boxes2.add(Sphere(Point3.random(0, 165), 10, white)) world.add( Translate(RotateY(BVHNode(boxes2.objects, time0, time1), 15), Vec3(-100, 270, 395))) world_bvh = BVHNode(world.objects, time0, time1) lookfrom = Point3(478, 278, -600) lookat = Point3(278, 278, 0) vup = Vec3(0, 1, 0) vfov = 40 dist_to_focus: float = 10 aperture: float = 0 cam = Camera(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus, time0, time1) return world_bvh, cam