def bounding_box_on_time(self, time: float) -> AABB:
     box = AABB(
         self.get_center(time) -
         Vector3(self._radius, self._radius, self._radius),
         self.get_center(time) +
         Vector3(self._radius, self._radius, self._radius))
     return box
class HitRecord(object):
    t: float = 0.0
    hit_point: Vector3 = Vector3(0.0, 0.0, 0.0)
    hit_point_normal: Vector3 = Vector3(0.0, 0.0, 0.0)
    u: float = 0.0
    v: float = 0.0
    material: Material = None
Beispiel #3
0
    def calculate_ray_color(self, ray: Ray, depth: float):
        has_hit, hit_record = self._bvh_world.hit(ray=ray,
                                                  t_min=0.001,
                                                  t_max=float('inf'))

        if has_hit is True:
            scattered, attenuation = hit_record.material.scatter(
                ray_incident=ray, hit_record=hit_record)

            emitted = hit_record.material.emitted(u=hit_record.u,
                                                  v=hit_record.v,
                                                  p=hit_record.hit_point)
            if depth < 50 and scattered is not None:
                return emitted + attenuation * self.calculate_ray_color(
                    ray=scattered, depth=depth + 1)
            else:
                return emitted

        else:
            # Ambient Color
            # return Vector3(0.0, 0.0, 0.0)
            ray_direction = Vector3.normalize(ray.direction)
            t = 0.5 * (ray_direction.y() + 1.0)
            return (1.0 - t) * Vector3(0.2, 0.2, 0.2) + t * Vector3(
                0.5, 0.7, 1.0)
Beispiel #4
0
    def _render_patch(self, patch_number: int, begin_row: int,
                      begin_column: int, patch_width: int, patch_height: int):
        """Render a patch of the image defined by {row} {column} with {width} and {height}"""
        logging.info(
            f'Beginning patch {patch_number}: ({begin_row} {begin_column}) with width {patch_width} and height {patch_height}'
        )

        max_color_value = 255.99
        result = list()
        for row in range(begin_row, begin_row - patch_height, -1):
            for column in range(begin_column, begin_column + patch_width):
                final_color = Vector3()
                for s in range(self.num_samples):
                    u = float(column + random.random()) / float(self.width)
                    v = float(row + random.random()) / float(self.height)

                    r = self.camera.get_ray(u=u, v=v)
                    final_color = final_color + self.calculate_ray_color(
                        ray=r, depth=0)

                final_color = final_color / self.num_samples

                # make the sqrt for the gamma correction
                final_color = Vector3(
                    math.sqrt(final_color.r()) * max_color_value,
                    math.sqrt(final_color.g()) * max_color_value,
                    math.sqrt(final_color.b()) * max_color_value)
                result.append((row, column, final_color))

        logging.info(
            f'Ending patch {patch_number} ({begin_row} {begin_column}) with width {patch_width} and height {patch_height}'
        )
        return result
    def random_in_unit_sphere():
        p = Vector3(1.0, 1.0, 1.0)
        while p.length() >= 1.0:
            p = 2.0 * Vector3(random.random(), random.random(),
                              random.random()) - Vector3(1, 1, 1)

        return p
Beispiel #6
0
    def build_from_w(self, n: Vector3):
        self._w = Vector3.normalize(n)
        if math.fabs(self._w.x()) > 0.9:
            a = Vector3(0, 1, 0)
        else:
            a = Vector3(1, 0, 0)

        self._v = Vector3.normalize(Vector3.cross(self._w, a))
        self._u = Vector3.cross(self._w, self._v)
Beispiel #7
0
    def first_light_scene():
        list_of_hitables = [
            Sphere(center=Vector3(0.0, -1000, 0.0), radius=1000, material=Lambertian(albedo=Vector3(0.9, 0.67, 0.25))),
            Sphere(center=Vector3(0.0, 2, 0.0), radius=2, material=Lambertian(albedo=Vector3(0.7, 0.8, 0.1))),
            Sphere(center=Vector3(0.0, 7, 0.0), radius=2, material=DiffuseLight(albedo=Vector3(1.0, 1.0, 1.0), texture=ConstantTexture(color=Vector3(4,4,4)))),
            XYRect(3, 5, 1, 3, -2, DiffuseLight(albedo=Vector3(1.0, 1.0, 1.0), texture=ConstantTexture(color=Vector3(1, 1, 1))))
        ]

        return list_of_hitables
Beispiel #8
0
 def __init__(self,
              albedo: Vector3 = Vector3(1.0, 1.0, 1.0),
              texture: Texture = None):
     """ Lamberian Material
     :param albedo: albedo color of the material
     :type albedo: Vector3
     """
     super().__init__()
     self._albedo = albedo
     self._texture = ConstantTexture(Vector3(
         1.0, 1.0, 1.0)) if texture is None else texture
Beispiel #9
0
    def surrounding_box(box0, box1):  # try to use annotations
        smallest = Vector3(
            min(box0.min.x(), box1.min.x()),
            min(box0.min.y(), box1.min.y()),
            min(box0.min.z(), box1.min.z()),
        )

        biggest = Vector3(
            max(box0.max.x(), box1.max.x()),
            max(box0.max.y(), box1.max.y()),
            max(box0.max.z(), box1.max.z()),
        )

        return AABB(min=smallest, max=biggest)
 def random_cosine_direct():
     r1, r2 = random.random(), random.random()
     z = math.sqrt(1 - r2)
     phi = 2 * math.pi * r1
     x = math.cos(phi) * 2 * math.sqrt(r2)
     y = math.sin(phi) * 2 * math.sqrt(r2)
     return Vector3(x, y, z)
Beispiel #11
0
    def hit(self, ray: Ray, t_min: float, t_max: float) -> (bool, HitRecord):
        """Checks if the ray 'ray' hits with the plane between t_min and t_max.
        Returns true if there is a collision, false otherwise.
        Return the hitRecord information if the collision is true.
        """
        if ray.direction.y() == 0.0:
            return False, None

        t = (self._k - ray.origin.y()) / ray.direction.y()
        if t < t_min or t > t_max:
            return False, None

        x = ray.origin.x() + t * ray.direction.x()
        z = ray.origin.z() + t * ray.direction.z()

        if x < self._x0 or x > self._x1 or z < self._z0 or z > self._z1:
            return False, None

        record = HitRecord()
        record.t = t
        record.hit_point = ray.point_at_parameter(record.t)
        record.hit_point_normal = Vector3(0, 1, 1)

        record.u = (x - self._x0) / (self._x1 - self._x0)
        record.v = (z - self._z0) / (self._z1 - self._z0)
        record.material = self._material

        return True, record
Beispiel #12
0
 def perlin_generate(self):
     p = list()
     for i in range(256):
         p.append(
             Vector3.normalize(
                 Vector3(-1 + 2 * random.random(), -1 + 2 * random.random(),
                         -1 + 2 * random.random())))
     return p
 def __init__(self, width, height, color_matrix=None):
     self.width = width
     self.height = height
     if color_matrix is None:
         self.color_matrix = list()
         for row in range(self.height):
             self.color_matrix.append([Vector3(0.0, 0.0, 0.0)] * self.width)
     else:
         self.color_matrix = color_matrix
Beispiel #14
0
    def random_to_sphere(self, radius: float,
                         distance_squared: float) -> Vector3:
        r1 = random.random()
        r2 = random.random()
        z = 1 + r2 * (
            math.sqrt(1 - self._radius * self._radius / distance_squared) - 1)
        phi = 2 * math.pi * r1
        x = math.cos(phi) * math.sqrt(1 - z * z)
        y = math.sin(phi) * math.sqrt(1 - z * z)

        return Vector3(x, y, z)
Beispiel #15
0
    def trilineart_interp(self, c, u, v, w):
        uu = u * u * (3 - 2 * u)
        vv = v * v * (3 - 2 * v)
        ww = w * w * (3 - 2 * w)

        accum = 0
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    weight_v = Vector3(u - i, v - j, w - k)
                    accum += (i * uu + (1 - i) * (1 - uu)) * \
                             (j * vv + (1 - j) * (1 - vv)) * \
                             (k * ww + (1 - k) * (1 - ww)) * Vector3.dot(c[i * 2 + j * 2 + k], weight_v)
        return accum
Beispiel #16
0
    def value(self, u: float, v: float, p: Vector3) -> Vector3:
        i = (self.uoffset - u) * (self._width - 1)
        j = (self.voffset + v) * (self._height - 1)
        i = i % self._width
        j = j % self._height
        # i = MathUtils.clamp(i, 0, self._width - 1)
        # j = MathUtils.clamp(j, 0, self._height - 1)

        pix = self._image.load()
        r = int(pix[i, j][0]) / 255.0
        g = int(pix[i, j][1]) / 255.0
        b = int(pix[i, j][2]) / 255.0

        return Vector3(r, g, b)
    def hit(self, ray: Ray, t_min: float, t_max: float) -> (bool, HitRecord):
        """Checks if the ray 'ray' hits with any of the walls between t_min and t_max."""
        # db = False
        has_hit, rec1 = self._boundary.hit(ray=ray,
                                           t_min=-float('inf'),
                                           t_max=float('inf'))
        if has_hit is True:
            has_hit_again, rec2 = self._boundary.hit(ray=ray,
                                                     t_min=rec1.t + 0.0001,
                                                     t_max=float('inf'))
            if has_hit_again is True:

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

                # if db:
                #     print(f't0 t1 {rec1.t} {rec2.t}')
                if rec1.t >= rec2.t:
                    return False, None
                if rec1.t < 0:
                    rec1.t = 0

                distance_inside_boundary = (rec2.t -
                                            rec1.t) * ray.direction.length()
                hit_distance = -(1 / self._density) * math.log(
                    random.random())  # base 10 ?

                # if db:
                #     print(f'DATA: {hit_distance} {distance_inside_boundary} {hit_distance < distance_inside_boundary}')

                if hit_distance < distance_inside_boundary:
                    # if db:
                    #     print(f'hit distance = {hit_distance}')
                    hit_record = HitRecord()
                    hit_record.t = rec1.t + hit_distance / ray.direction.length(
                    )
                    # if db:
                    #     print(f'rec.t = {hit_record.t}')
                    hit_record.hit_point = ray.point_at_parameter(hit_record.t)
                    # if db:
                    #     print(f'rec.hit_point = {hit_record.hit_point}')
                    hit_record.hit_point_normal = Vector3(1, 0, 0)
                    hit_record.material = self._phase_function

                    return True, hit_record

        return False, None
Beispiel #18
0
    def one_sphere_noise() -> (list, Camera):
        lookfrom = Vector3(13, 2, 3)
        lookat = Vector3(0, 0, 0)
        camera = Camera(lookfrom=lookfrom, lookat=lookat, vectorup=Vector3(0.0, 1.0, 0.0),
                        vfov=20.0, aspect=16 / 9, aperture=0.0,
                        focus_dist=10.0, t0=0.0, t1=1.0)

        pertext = NoiseTexture(scale=1.0)

        list_of_hitables = [
            Sphere(Vector3(0, -1000, 0), 1000, Lambertian(albedo=Vector3(1.0, 1.0, 1.0), texture=pertext)),
            Sphere(Vector3(0, 2, 0), 2, Lambertian(albedo=Vector3(1.0, 1.0, 1.0), texture=pertext))
        ]

        return list_of_hitables, camera
Beispiel #19
0
    def one_sphere_world():
        lookfrom = Vector3(12, 5, 3)
        lookat = Vector3(0, 2, -1)
        camera = Camera(lookfrom=lookfrom, lookat=lookat, vectorup=Vector3(0.0, 1.0, 0.0),
                        vfov=20.0, aspect=16 / 9, aperture=0.0,
                        focus_dist=10.0, t0=0.0, t1=1.0)

        checker_texture = CheckerTexture(texture0=ConstantTexture(Vector3(0.2, 0.3, 0.1)), texture1=ConstantTexture(Vector3(0.9, 0.9, 0.9)))

        script_dir = os.path.dirname(__file__)
        texture_filepath = os.path.join(script_dir, r'../resources/textures/google-maps.jpg')
        world_texture = ImageTexture(texture_file_path=texture_filepath, uoffset=0.1)
        texture_filepath = os.path.join(script_dir, r'../resources/textures/tiled-background-with-stripes-and-splatter_256x256.jpg')
        colors_texture = ImageTexture(texture_file_path=texture_filepath)

        list_of_hitables = [
            # Sphere(center=Vector3(0.0, -1000, 0.0), radius=1000,
            #        material=Lambertian(albedo=Vector3(1.0, 1.0, 1.0), texture=colors_texture)),
            XZRect(-20, 20, -20, 20, 0, material=Lambertian(albedo=Vector3(1.0, 1.0, 1.0), texture=colors_texture)),
            Sphere(center=Vector3(0, 2, 0), radius=2.0, material=Lambertian(albedo=Vector3(1.0, 1.0, 1.0), texture=world_texture)),
            Sphere(center=Vector3(0, 1.0, -3), radius=1.0,material=Lambertian(albedo=Vector3(1.0, 1.0, 1.0), texture=checker_texture))
        ]
        return list_of_hitables, camera
Beispiel #20
0
    def scatter(self, ray_incident: Ray, hit_record: HitRecord):

        reflected_vector = Vector3.reflect(
            Vector3.normalize(ray_incident.direction),
            hit_record.hit_point_normal)
        attenuation = Vector3(1.0, 1.0, 1.0)

        refracted_vector = Vector3.refract(incident=ray_incident.direction,
                                           normal=hit_record.hit_point_normal,
                                           n1=1.0,
                                           n2=self._refraction_index)
        reflect_probability = self.schlick(incident=ray_incident.direction,
                                           normal=hit_record.hit_point_normal,
                                           n1=1.0,
                                           n2=self._refraction_index)

        if random.random() < reflect_probability:
            scattered = Ray(hit_record.hit_point, reflected_vector,
                            ray_incident.time)
        else:
            scattered = Ray(hit_record.hit_point, refracted_vector,
                            ray_incident.time)

        return scattered, attenuation
Beispiel #21
0
 def bounding_box(self, t0: float, t1: float) -> AABB:
     return AABB(min=Vector3(self._x0, self._y0, self._k - 0.0001),
                 max=Vector3(self._x1, self._y1, self._k + 0.0001))
Beispiel #22
0
 def __init__(self):
     super().__init__()
     self._u = Vector3()
     self._v = Vector3()
     self._w = Vector3()
Beispiel #23
0
    def the_next_week_final():
        white_mat = Lambertian(albedo=Vector3(0.73, 0.73, 0.73))
        ground_mat = Lambertian(albedo=Vector3(0.48, 0.83, 0.53))
        light = DiffuseLight(albedo=Vector3(1.0, 1.0, 1.0), texture=ConstantTexture(color=Vector3(1,1,1)))

        lookfrom = Vector3(0, 150, -500)
        lookat = Vector3(200, 150, 0)
        camera = Camera(lookfrom=lookfrom, lookat=lookat, vectorup=Vector3(0.0, 1.0, 0.0),
                        vfov=60.0, aspect=16 / 9, aperture=0.0,
                        focus_dist=(lookfrom - lookat).length(),
                        t0=0.0, t1=1.0)

        list_of_hitables = list()

        for i in range(20):
            for j in range(20):
                w = 100
                x0 = -1000 + i * w
                z0 = -1000 + j * w
                y0 = 0
                x1 = x0 + w
                y1 = 100 * (random.random() + 0.01)
                z1 = z0 + w
                print(Vector3(x0, y0, z0))
                print(Vector3(x1, y1, z1))
                list_of_hitables.append(
                    Box(Vector3(x0, y0, z0), Vector3(x1, y1, z1), ground_mat)
                )

        list_of_hitables.append(
            YZRect(123, 423, 147, 412, 554, light)
        )

        list_of_hitables.append(
            Sphere(center=Vector3(400, 400, 200), radius=50,
                   material=Lambertian(albedo=Vector3(1.0, 1.0, 1.0),
                                       texture=ConstantTexture(color=Vector3(0.7, 0.3, 0.1))
                                       ),
                   center_destiny=Vector3(430, 400, 200), time0=0, time1=1)
        )
        list_of_hitables.append(
            Sphere(center=Vector3(260, 150, 45), radius=50,
                   material=Dielectric(refraction_index=1.5))
        )
        list_of_hitables.append(
            Sphere(center=Vector3(0, 150, 145), radius=50,
                   material=Metal(albedo=Vector3(0.8, 0.8, 0.9), fuzz=10.0))
        )
        boundary01 = Sphere(center=Vector3(360, 150, 145), radius=70, material=Dielectric(refraction_index=1.5))
        list_of_hitables.append(
            ConstantVolume(boundary=boundary01, density=0.2, texture=ConstantTexture(Vector3(0.2, 0.4, 0.9)))
        )
        boundary02 = Sphere(center=Vector3(0, 0, 0), radius=5000, material=Dielectric(refraction_index=1.5))
        list_of_hitables.append(
            ConstantVolume(boundary=boundary02, density=0.0001, texture=ConstantTexture(Vector3(1.0, 1.0, 1.0)))
        )

        return list_of_hitables, camera
 def value(self, u: float, v: float, p: Vector3):
     # return Vector3(1, 1, 1) * 0.5 * (1 + self._noise.turb(p=self._scale * p))
     # return Vector3(1, 1, 1) * self._noise.turb(self._scale * p)
     return Vector3(1, 1, 1) * 0.5 * (
         1 + math.sin(self._scale * p.z() + 10 * self._noise.turb(p)))
Beispiel #25
0
 def emitted(self, u: float, v: float, p: Vector3) -> Vector3:
     return Vector3(0.0, 0.0, 0.0)
Beispiel #26
0
 def random_spheres_scene():
     world = list()
     world.append(
         Sphere(Vector3(0, -1000, 0), 1000, Lambertian(Vector3(0.5, 0.5))))
     for a in range(-11, 11):
         for b in range(-11, 11):
             center = Vector3(a + 0.9 * random.random(), 0.2,
                              b + 0.9 * random.random())
             if (center - Vector3(1, 0.2, 0)).length() > 0.9:
                 choose_mat = random.random()
                 if choose_mat < 0.8:
                     world.append(
                         Sphere(
                             center, 0.2,
                             Lambertian(
                                 Vector3(random.random() * random.random(),
                                         random.random() * random.random(),
                                         random.random() *
                                         random.random()))))
                 elif choose_mat < 0.95:
                     world.append(
                         Sphere(
                             center, 0.2,
                             Metal(
                                 Vector3(0.5 * (1 + random.random()),
                                         0.5 * (1 + random.random()),
                                         0.5 * (1 + random.random())),
                                 0.5 * random.random())))
                 else:
                     world.append(Sphere(center, 0.2, Dielectric(1.5)))
     world.append(Sphere(Vector3(0, 1, 0), 1.0, Dielectric(1.5)))
     world.append(
         Sphere(Vector3(-4, 1, 0), 1.0, Lambertian(Vector3(0.4, 0.2, 0.1))))
     world.append(
         Sphere(Vector3(4, 1, 0), 1.0, Metal(Vector3(0.7, 0.6, 0.5), 0.0)))
     return world
Beispiel #27
0
    def random_in_unit_disk(self):
        p = Vector3(1.0, 1.0, 0.0)
        while p.length() >= 1.0:
            p = 2.0 * Vector3(random.random(), random.random(), 0) - Vector3(1, 1, 0)

        return p
Beispiel #28
0
    def cornell_box():

        red_mat = Lambertian(albedo=Vector3(0.65, 0.05, 0.05))
        white_mat = Lambertian(albedo=Vector3(0.73, 0.73, 0.73))
        green_mat = Lambertian(albedo=Vector3(0.12, 0.45, 0.15))
        light = DiffuseLight(albedo=Vector3(1.0, 1.0, 1.0), texture=ConstantTexture(color=Vector3(4, 4, 4)))

        box01 = Box(p0=Vector3(130, 0, 65), p1=Vector3(295, 165, 230), material=white_mat)
        box02 = Box(p0=Vector3(265, 0, 295), p1=Vector3(430, 330, 460), material=white_mat)

        list_of_hitables = [
            FlipNormals(YZRect(0, 555, 0, 555, 555, green_mat)),
            YZRect(0, 555, 0, 555, 0, red_mat),
            XZRect(113, 443, 127, 432, 554, light),
            FlipNormals(XZRect(0, 555, 0, 555, 555, white_mat)),
            XZRect(0, 555, 0, 555, 0, white_mat),
            FlipNormals(XYRect(0, 555, 0, 555, 555, white_mat)),
            ConstantVolume(boundary=box01, density=0.01, texture=ConstantTexture(Vector3(0.95, 0.95, 0.95))),
            ConstantVolume(boundary=box02, density=0.01, texture=ConstantTexture(Vector3(0.05, 0.05, 0.05)))
        ]

        lookfrom = Vector3(278, 278, -800)
        lookat = Vector3(278, 278, 0.0)
        camera = Camera(lookfrom=lookfrom, lookat=lookat, vectorup=Vector3(0.0, 1.0, 0.0),
                        vfov=40.0, aspect=16/9, aperture=0.0,
                        focus_dist=(lookfrom - lookat).length(),
                        t0=0.0, t1=1.0)

        return list_of_hitables, camera