Пример #1
0
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
Пример #2
0
def scan_line(j: int, background: Color, world: BVHNode, cam: Camera,
              image_width: int, image_height: int, samples_per_pixel: int,
              max_depth: int) -> Img:
    img = Img(image_width, 1)
    for i in range(image_width):
        pixel_color = Color(0, 0, 0)
        for s in range(samples_per_pixel):
            u: float = (i + random_float()) / (image_width - 1)
            v: float = (j + random_float()) / (image_height - 1)
            r: Ray = cam.get_ray(u, v)
            pixel_color += ray_color(r, background, world, max_depth)
        img.write_pixel(i, 0, pixel_color, samples_per_pixel)
    print(f"Scanlines remaining: {j} ", end="\r")
    return img
Пример #3
0
    def hit(self, r: Ray, t_min: float, t_max: float) -> Optional[HitRecord]:
        rec1 = self.boundary.hit(r, -np.inf, np.inf)
        if rec1 is None:
            return None
        rec2 = self.boundary.hit(r, rec1.t + 0.0001, np.inf)
        if rec2 is None:
            return None

        if rec1.t < t_min:
            rec1.t = t_min
        if rec1.t < 0:
            rec1.t = 0
        if rec2.t > t_max:
            rec2.t = t_max

        if rec1.t >= rec2.t:
            return None

        ray_length = r.direction().length()
        distance_inside_boundary = (rec2.t - rec1.t) * ray_length
        hit_distance = self.neg_inv_density * np.log(random_float())

        if hit_distance > distance_inside_boundary:
            return None

        t = rec1.t + hit_distance / ray_length
        p = r.at(t)
        rec = HitRecord(p, t, self.phase_function)
        rec.normal = Vec3(1, 0, 0)
        rec.front_face = True

        return rec
Пример #4
0
    def scatter(self, r_in: Ray, rec: HitRecord) \
            -> Optional[Tuple[Ray, Color]]:
        if rec.front_face:
            etai_over_etat = 1 / self.ref_idx
        else:
            etai_over_etat = self.ref_idx

        unit_direction: Vec3 = r_in.direction().unit_vector()
        cos_theta: float = min(-unit_direction @ rec.normal, 1)
        sin_theta: float = np.sqrt(1 - cos_theta**2)
        reflect_prob: float = self.schlick(cos_theta, etai_over_etat)

        if etai_over_etat * sin_theta > 1 or random_float() < reflect_prob:
            # total internal reflection
            reflected: Vec3 = unit_direction.reflect(rec.normal)
            scattered = Ray(rec.p, reflected)
        else:
            # refraction
            refracted: Vec3 = unit_direction.refract(
                rec.normal, etai_over_etat
            )
            scattered = Ray(rec.p, refracted)

        attenuation = Color(1, 1, 1)
        return scattered, attenuation
Пример #5
0
 def random_in_unit_sphere() -> Vec3:
     """
     This method is modified from:
     https://karthikkaranth.me/blog/generating-random-points-in-a-sphere/#better-choice-of-spherical-coordinates
     """
     u = random_float()
     v = random_float()
     theta = u * 2 * cp.pi
     phi = cp.arccos(2 * v - 1)
     r = cp.cbrt(random_float())
     sinTheta = cp.sin(theta)
     cosTheta = cp.cos(theta)
     sinPhi = cp.sin(phi)
     cosPhi = cp.cos(phi)
     x = r * sinPhi * cosTheta
     y = r * sinPhi * sinTheta
     z = r * cosPhi
     return Vec3(x, y, z)
Пример #6
0
    def get_ray(self, s: float, t: float) -> Ray:
        rd: Vec3 = Vec3.random_in_unit_disk() * self.lens_radius
        offset: Vec3 = self.u * rd.x() + self.v * rd.y()

        return Ray(
            self.origin + offset,
            (self.lower_left_corner
             + self.horizontal*s + self.vertical*t
             - self.origin - offset),
            random_float(self.time0, self.time1)
        )
Пример #7
0
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
Пример #8
0
 def random_in_unit_disk():
     while True:
         p = Vec3(random_float(-1, 1), random_float(-1, 1), 0)
         if p.length_squared() >= 1:
             continue
         return p
Пример #9
0
 def random_unit_vector() -> Vec3:
     a: float = random_float(0, 2 * np.pi)
     z: float = random_float(-1, 1)
     r: float = np.sqrt(1 - z**2)
     return Vec3(r * np.cos(a), r * np.sin(a), z)
Пример #10
0
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