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)
Exemplo n.º 2
0
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)))
Exemplo n.º 3
0
    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')
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
    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])
Exemplo n.º 6
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))
Exemplo n.º 7
0
    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))
Exemplo n.º 8
0
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])
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
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)))
Exemplo n.º 12
0
        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)