def random_scene(): l = [] l.append(Sphere(Vec3(0, -1000, -1), 1000, Lambertian(Vec3(0.5, 0.5, 0.5)))) for a in range(-11, 11): for b in range(-11, 11): choose_mat = random() center = Vec3(a + 0.9 * random(), 0.2, b + 0.9 * random()) if (center - Vec3(4, 0.2, 0)).length() > 0.9: if choose_mat < 0.8: #diffuse l.append( MovingSphere( center, center + Vec3(0.0, 0.5 * random(), 0.0), 0.0, 1.0, 0.2, Lambertian( Vec3(random() * random(), random() * random(), random() * random())))) elif choose_mat < 0.95: #metal l.append( Sphere( center, 0.2, Metal( Vec3(0.5 * (1 + random()), 0.5 * (1 + random()), 0.5 * (1 + random())), 0.5 * random()))) else: #glass l.append(Sphere(center, 0.2, Dielectric(1.5))) l.append(Sphere(Vec3(0, 1, 0), 1.0, Dielectric(1.5))) l.append(Sphere(Vec3(-4, 1, 0), 1.0, Lambertian(Vec3(0.4, 0.2, 0.1)))) l.append(Sphere(Vec3(4, 1, 0), 1.0, Metal(Vec3(0.7, 0.6, 0.5), 0.0))) return HitableList(l)
def main(): # image dimensions (pixel) nx = 200 ny = 100 # number of samples (rays) per pixel ns = 100 # define camera lookfrom = np.array([-3., 3., 3.]) lookat = np.array([0., 0., 0.]) vfov = np.pi/9 aperture = 1. focus_dist = np.linalg.norm(lookat - lookfrom) cam = Camera(lookfrom, lookat, np.array([0., 1., 0.]), vfov, nx / ny, aperture, focus_dist) # define scene geometry scene = SurfaceAssembly() scene.add_object(Sphere(np.array([ 0., 0., 0.]), 0.5, Lambertian(np.array([0.1, 0.2, 0.5])))) scene.add_object(Sphere(np.array([ 1., 0., 0.]), 0.5, Metal(np.array([0.8, 0.6, 0.2]), 1.0))) # imitate hollow glass sphere scene.add_object(Sphere(np.array([-1., 0., 0.]), 0.5, Dielectric(1.5))) scene.add_object(Sphere(np.array([-1., 0., 0.]), -0.45, Dielectric(1.5))) # large sphere imitating ground floor scene.add_object(Sphere(np.array([0., -100.5, 0.]), 100., Lambertian(np.array([0.8, 0.8, 0.0])))) # render image im = render_image(nx, ny, ns, scene, cam) imageio.imwrite('depth_of_field.png', im.transpose((1, 0, 2)))
def test_dielectric_scatter(self): dielmat = Dielectric(0.2) # ray specified by origin and direction ray = Ray(np.array([0.2, 0., 0.3]), np.array([0.1, -0.05, -1.1])) # hit record point = np.array([0.3, 0.4, -0.5]) normal = unit_vector(np.array([0.2, 0.9, -0.1])) rec = HitRecord(point, normal, dielmat) scattered, att = dielmat.scatter(ray, rec) self.assertEqual( np.linalg.norm(scattered.origin - point), 0, msg='origin of scattered ray must agree with hit record point') # reference directions of scattered ray (can be either reflected or refracted) reflect_ref = np.array( [0.054686541501393009, -0.20612619488986597, -0.97699609720757918]) refract_ref = np.array( [0.22585143494322246, 0.92588833091527412, -0.30285628276298776]) err_reflect = np.linalg.norm(scattered.direction - reflect_ref) err_refract = np.linalg.norm(scattered.direction - refract_ref) self.assertAlmostEqual( min(err_reflect, err_refract), 0, delta=1e-14, msg='direction of scattered ray must agree with reference')
def random_scene(): hitables = [] hitables.append( Sphere(Vec3(0, -1000, 0), 1000, Lambertian(Vec3(0.5, 0.5, 0.5)))) for a in range(-11, 11): for b in range(-11, 11): choose_mat = random() center = Vec3(a + 0.9 * random(), 0.2, b + 0.9 * random()) if (center - Vec3(4, 0.2, 0)).length > 0.9: if choose_mat < 0.8: hitables.append( Sphere( center, 0.2, Lambertian( Vec3(random() * random(), random() * random(), random() * random())))) elif choose_mat < 0.95: hitables.append( Sphere( center, 0.2, Metal( Vec3(0.5 * (1 + random()), 0.5 * (1 + random()), 0.5 * (1 + random())), 0.5 * random()))) else: hitables.append(Sphere(center, 0.2, Dielectric(1.5))) hitables.append(Sphere(Vec3(0, 1, 0), 1.0, Dielectric(1.5))) hitables.append( Sphere(Vec3(-4, 1, 0), 1.0, Lambertian(Vec3(0.4, 0.2, 0.1)))) hitables.append(Sphere(Vec3(4, 1, 0), 1.0, Metal(Vec3(0.7, 0.6, 0.5), 0.0))) return HitableList(hitables)
def basic(self): self.lookfrom = np.array([3.0, 3.0, 2.0]) self.lookat = np.array([0.0, 0.0, -1.0]) self.vup = np.array([0.0, 1.0, 0.0]) self.vfov = 20.0 # self.aperature = 2.0 # self.focus_dist = ru.length(self.lookfrom - self.lookat) self.camera = Camera(self.img_width, self.img_height, self.lookfrom, self.lookat, self.vup, self.vfov, self.aperature, self.focus_dist) mat_ground = Lambertian(np.array([0.8, 0.8, 0.0])) mat_center = Lambertian(np.array([0.1, 0.2, 0.5])) mat_left = Dielectric(1.5) mat_right = Metal(np.array([0.8, 0.6, 0.2]), 0.0) self.world.add(Sphere(np.array([0.0, -100.5, -1.0]), 100, mat_ground)) self.world.add(Sphere(np.array([0.0, 0.0, -1.0]), 0.5, mat_center)) self.world.add(Sphere(np.array([-1.0, 0.0, -1.0]), 0.5, mat_left)) self.world.add(Sphere(np.array([-1.0, 0.0, -1.0]), -0.45, mat_left)) self.world.add(Sphere(np.array([1.0, 0.0, -1.0]), 0.5, mat_right)) self.world.add( BVHNode(self.world.objects, 0, len(self.world.objects), 0, 1)) self.background = np.array([0.7, 0.8, 1.0])
def random_spheres(self): self.lookfrom = np.array([13.0, 2.0, 3.0]) self.lookat = np.array([0.0, 0.0, 0.0]) self.vfov = 20.0 self.aperature = 0.1 self.background = np.array([0.7, 0.8, 1.0]) self.camera = Camera(self.img_width, self.img_height, self.lookfrom, self.lookat, self.vup, self.vfov, self.aperature, self.focus_dist) mat_ground = Lambertian(np.array([0.5, 0.5, 0.5])) self.world.add(Sphere(np.array([0.0, -1000, 0.0]), 1000, mat_ground)) for a in range(-11, 11): for b in range(-11, 11): choose_mat = ru.get_random() center = np.array([ a + 0.9 * ru.get_random(), 0.2, b + 0.9 * ru.get_random() ]) if ru.length(center - np.array([4.0, 0.2, 0.0])) > 0.9: sphere_material: Material if choose_mat < 0.8: albedo = ru.get_random_point() * ru.get_random_point() sphere_material = Lambertian(albedo) elif choose_mat < 0.95: albedo = ru.get_random_point_in_range(0.5, 1.0) fuzz = ru.get_random_in_range(0.0, 0.5) sphere_material = Metal(albedo, fuzz) else: sphere_material = Dielectric(1.5) self.world.add(Sphere(center, 0.2, sphere_material)) mat1 = Dielectric(1.5) self.world.add(Sphere(np.array([0.0, 1.0, 0.0]), 1.0, mat1)) mat2 = Lambertian(np.array([0.4, 0.2, 0.1])) self.world.add(Sphere(np.array([-4.0, 1.0, 0.0]), 1.0, mat2)) mat3 = Metal(np.array([0.7, 0.6, 0.5]), 0.0) self.world.add(Sphere(np.array([4.0, 1.0, 0.0]), 1.0, mat3)) # BVH implementation self.world.add( BVHNode(self.world.objects, 0, len(self.world.objects), 0, 1))
def my_scene(self): self.vfov = 65 self.lookfrom = np.array([800, 180, 200]) self.lookat = np.array([200, 0, 800]) self.background = np.array([0, 0, 0]) self.camera = Camera(self.img_width, self.img_height, self.lookfrom, self.lookat, self.vup, self.vfov, self.aperature, self.focus_dist) light = DiffuseLight(np.array([1, 1, 1])) mirror = Metal(np.array([0.95, 0.95, 0.95]), 0) mat_ground = Lambertian(np.array([0.5, 0.5, 0.5])) glass = Dielectric(2.0) mat_sphere = Lambertian(np.array([0.8, 0.8, 0.8])) self.world.add(XZRectangle(200, 800, 200, 800, 0, mat_ground)) self.world.add(XYRectangle(425, 575, 0, 100, 700, light)) self.world.add(XYRectangle(425, 575, 0, 100, 310, light)) self.world.add(YZRectangle(0, 250, 200, 800, 200, mirror)) self.world.add(YZRectangle(0, 250, 200, 800, 800, mirror)) self.world.add(XYRectangle(200, 800, 0, 250, 800, mirror)) self.world.add(XYRectangle(200, 800, 0, 250, 200, mirror)) for x in range(470, 531, 30): for z in range(535, 474, -30): self.world.add(Sphere(np.array([x, 15, z]), 15, glass)) for x in range(485, 516, 30): for z in range(520, 489, -30): self.world.add( Sphere(np.array([x, 15 * (1 + np.sqrt(3)), z]), 15, glass)) self.world.add( Sphere(np.array([500, 15 * (1 + 2 * np.sqrt(3)), 505]), 15, glass)) self.world.add(Sphere(np.array([500, 15, 445]), 15, mirror)) self.world.add(Sphere(np.array([500, 15, 565]), 15, mirror)) self.world.add(Sphere(np.array([440, 15, 505]), 15, mat_sphere)) self.world.add(Sphere(np.array([560, 15, 505]), 15, mat_sphere)) dist = 15 * np.sqrt(2) self.world.add( Sphere(np.array([470 - dist, 15, 535 + dist]), 15, light)) self.world.add( Sphere(np.array([530 + dist, 15, 535 + dist]), 15, light)) self.world.add( Sphere(np.array([470 - dist, 15, 475 - dist]), 15, light)) self.world.add( Sphere(np.array([530 + dist, 15, 475 - dist]), 15, light)) self.world.add( BVHNode(self.world.objects, 0, len(self.world.objects), 0, 1))
def get_small_world() -> World: mat_ground = Lambertian(Color(.8, .8, .3)) ground = Sphere(Vector(0, -100.5, -1), 100, mat_ground) mat_center = Lambertian(Color(.7, .3, .3)) center = Sphere(Vector(0, 0, -1), .5, mat_center) mat_left = Metal(Color(.8, .8, .8)) left = Sphere(Vector(-1, 0, -1), .5, mat_left) mat_right = Dielectric(1.5) right = Sphere(Vector(1, 0, -1), .5, mat_right) return World([ground, center, left, right])
def random_scene(): """Generate a random scene.""" result = [] sphere = Sphere(Vec3(0, -1000, 0), 1000, Lambertian(Vec3(0.5, 0.5, 0.5))) result.append(sphere) for a in range(-11, 11): for b in range(-11, 11): choose_mat = random() center = Vec3(a + 0.9 * random(), 0.2, b + 0.9 * random()) if (center - Vec3(4, 0.2, 0)).length > 0.9: if choose_mat < 0.8: # make diffuse sphere = Sphere( center, 0.2, Lambertian( Vec3(random() * random(), random() * random(), random() * random()))) elif choose_mat < 0.95: # make metallic sphere = Sphere( center, 0.2, Metal( Vec3(0.5 * (1 + random()), 0.5 * (1 + random()), 0.5 * (1 + random())), 0.5 * random())) else: # make glassy sphere = Sphere(center, 0.2, Dielectric(1.5)) result.append(sphere) result.append(Sphere(Vec3(0, 1, 0), 1.0, Dielectric(1.5))) result.append(Sphere(Vec3(-4, 1, 0), 1.0, Lambertian(Vec3(0.4, 0.2, 0.1)))) result.append(Sphere(Vec3(4, 1, 0), 1.0, Metal(Vec3(0.7, 0.6, 0.5), 0.0))) return Hitable_List(result)
def get_world() -> World: world = [] glass = Dielectric(1.5) # Ground ground_mat = Lambertian(Color(0.5, 0.5, 0.5)) world.append(Sphere(Vector(0, -1000, 0), 1000, ground_mat)) # Marbles for x in range(-11, 11): for z in range(-11, 11): choose_material = random() material: Material center = Vector(x + .9 * random(), .2, z + .9 * random()) if (center - Vector(4, .2, 0)).norm() <= .9: continue if choose_material < .8: # Diffuse albedo = Color(*(random(3) * random(3))) material = Lambertian(albedo) elif choose_material < .95: # Metal albedo = Color(*(random(3) * .5 + .5)) fuzz = random() * .4 material = Metal(albedo, fuzziness=fuzz) else: # Glass material = glass world.append(Sphere(center, .2, material)) # Big Spheres world.append(Sphere(Vector(4, 1, 0), 1.0, glass)) world.append(Sphere(Vector(-4, 1, 0), 1.0, Lambertian(Color(.6, .1, .1)))) world.append(Sphere(Vector(0, 1, 0), 1.0, Metal(Color(.7, .6, .5)))) return World(world)
def main(): # image dimensions (pixel) nx = 1200 ny = 800 # number of samples (rays) per pixel ns = 10 # define camera lookfrom = np.array([13., 2., 3.]) lookat = np.zeros(3) vfov = np.pi / 9 aperture = 0.1 focus_dist = 10.0 cam = Camera(lookfrom, lookat, np.array([0., 1., 0.]), vfov, nx / ny, aperture, focus_dist) # define scene geometry scene = SurfaceAssembly() # three large spheres scene.add_object( Sphere(np.array([4., 1., 0.]), 1.0, Metal(np.array([0.7, 0.6, 0.5]), 0.))) scene.add_object(Sphere(np.array([0., 1., 0.]), 1.0, Dielectric(1.5))) scene.add_object( Sphere(np.array([-4., 1., 0.]), 1.0, Lambertian(np.array([0.4, 0.2, 0.1])))) # smaller spheres with random parameters for a in range(-11, 12): for b in range(-11, 12): center = np.array([ a + 0.9 * np.random.rand(), 0.2 + 0.1 * np.random.rand(), b + 0.9 * np.random.rand() ]) # random choice between diffusive, metal or dielectric (glass) choose_mat = np.random.choice(3, p=[0.8, 0.15, 0.05]) if choose_mat == 0: # diffusive scene.add_object( Sphere( center, 0.2, Lambertian(np.random.triangular(0., 0.2, 1., size=3)))) elif choose_mat == 1: # metal scene.add_object( Sphere( center, 0.2, Metal(0.5 * (1 + np.random.rand(3)), 0.5 * np.random.rand()))) else: # dielectric (glass) scene.add_object(Sphere(center, 0.2, Dielectric(1.5))) # huge sphere imitating ground floor scene.add_object( Sphere(np.array([0., -1000., 0.]), 1000., Lambertian(np.array([0.5, 0.5, 0.5])))) # render image im = render_image(nx, ny, ns, scene, cam) imageio.imwrite('random_scene.png', im.transpose((1, 0, 2)))
if idx[1] <= 0 or idx[1] >= shape[1]: return False if idx[2] < 0 or idx[2] >= shape[2]: return False else: raise ValueError return True if __name__ == '__main__': from material import Dielectric geom_list = [ DefaultMedium(material=Dielectric()), Cone(0, (1, 0, 0), 1, 1, Dielectric(), (0, 0, 2)), Cone(0, (1, 0, 0), 1, 1, Dielectric(), (0, 0, -2)) ] t = GeomBoxTree(geom_list) t.display_info() space = Cartesian(size=(5, 5, 5)) ex = space.get_ex_storage() print "ex shape:", ex.shape print "ex:", space.ex_index_to_space(0, 0, 0) print "ex:", space.ex_index_to_space(74, 75, 75) print "ex:", space.space_to_ex_index(0, 0, 0) print "ey:", space.space_to_ey_index(0, 0, 0) print "ez:", space.space_to_ez_index(0, 0, 0) print "hx:", space.space_to_hx_index(0, 0, 0) print "hy:", space.space_to_hy_index(0, 0, 0)