Exemple #1
0
 def hit(self, ray, tmin, tmax, hit_rec):
     radius = self.radius
     center = self.center
     material = self.material
     direction = ray.direction
     oc = ray.origin - center
     a = Vec.dot(direction, direction)
     b = Vec.dot(oc, direction)
     c = Vec.dot(oc, oc) - radius*radius
     discriminant = b*b - a*c
     if discriminant > 0:
         temp = (-b - sqrt(b*b-a*c))/a
         if temp < tmax and temp > tmin:
             hit_rec.t = temp
             hit_rec.p = ray.point_at_paramater(hit_rec.t)
             hit_rec.n = (hit_rec.p - center) / radius
             hit_rec.mat = material
             return True
         temp = (-b + sqrt(b * b - a * c)) / a
         if temp < tmax and temp > tmin:
             hit_rec.t = temp
             hit_rec.p = ray.point_at_paramater(hit_rec.t)
             hit_rec.n = (hit_rec.p - center) / radius
             hit_rec.mat = material
             return True
     return False
Exemple #2
0
 def scatter(self, r_in, hit_rec, attenuation, r_scattered):
     r_in_dir = r_in.direction
     reflected = Vec.reflect(r_in_dir, hit_rec.n)
     attenuation.set(1, 1, 1)
     refracted = Vec()
     if Vec.dot(r_in_dir, hit_rec.n) > 0:
         outward_normal = -hit_rec.n
         ior = self.ref_idx
         cosine = ior * Vec.dot(r_in_dir, hit_rec.n) / r_in_dir.length()
     else:
         outward_normal = hit_rec.n
         ior = 1.0 / self.ref_idx
         cosine = -Vec.dot(r_in_dir, hit_rec.n) / r_in_dir.length()
     if Dialectric.refract(r_in_dir, outward_normal, ior, refracted):
         reflect_prob = Dialectric.schlick(cosine, self.ref_idx)
     else:
         r_scattered.A = hit_rec.p
         r_scattered.B = reflected
         reflect_prob = 1.0
     if random() < reflect_prob:
         r_scattered.A = hit_rec.p
         r_scattered.B = reflected
     else:
         r_scattered.A = hit_rec.p
         r_scattered.B = refracted
     return True
Exemple #3
0
    def __init__(self,
                 aspect,
                 vfov,
                 aperture,
                 focus_dist,
                 lookfrom,
                 lookat,
                 vup=Vec(0, 1, 0)):
        self.lens_radius = aperture / 2
        theta = vfov * pi / 180
        half_height = tan(theta / 2)
        half_width = aspect * half_height

        self.origin = lookfrom

        w = Vec.unit_vector(lookfrom - lookat)
        u = Vec.unit_vector(Vec.cross(vup, w))
        v = Vec.cross(w, u)

        self.lower_left = self.origin - half_width * focus_dist * u - half_height * focus_dist * v - focus_dist * w
        self.horizontal = 2 * half_width * focus_dist * u
        self.vertical = 2 * half_height * focus_dist * v

        self.u = u
        self.v = v
Exemple #4
0
def random_in_unit_disk():
    p = Vec()
    while True:
        p.x = 2 * random()
        p.y = 2 * random()
        if Vec.dot(p, p) >= 1:
            break
    return p
Exemple #5
0
 def scatter(self, r_in, hit_rec, attenuation, r_scattered):
     reflected = Vec.reflect_mv(Vec.unit_vector(r_in.direction), hit_rec.n)
     r_scattered.A = hit_rec.p
     r_scattered.B = Sphere.random_in_unit_sphere().mul(
         self.fuzz).add(reflected)
     attenuation.x = self.albedo.x
     attenuation.y = self.albedo.y
     attenuation.z = self.albedo.z
     return Vec.dot(r_scattered.direction, hit_rec.n) > 0
Exemple #6
0
 def refract(v, n, ior, refracted):
     uv = Vec.unit_vector(v)
     dt = Vec.dot(uv, n)
     disc = 1 - ior * ior * (1 - dt * dt)
     if disc > 0:
         sqrt_disc = sqrt(disc)
         refracted.x = ior * (uv.x - n.x * dt) - n.x * sqrt_disc
         refracted.y = ior * (uv.y - n.y * dt) - n.y * sqrt_disc
         refracted.z = ior * (uv.z - n.z * dt) - n.z * sqrt_disc
         return True
     else:
         return False
Exemple #7
0
 def __init__(self,
              aspect_ratio=16 / 9,
              origin=Vec(0, 0, 0),
              viewport_height=2,
              focal_length=1.0):
     self.aspect_ratio = aspect_ratio
     self.viewport_height = viewport_height
     self.viewport_width = self.aspect_ratio * self.viewport_height
     self.focal_length = 1.0
     self.origin = Vec(0, 0, 0)
     self.horizontal = Vec(self.viewport_width, 0, 0)
     self.vertical = Vec(0, self.viewport_height, 0)
     self.lower_left_corner = self.origin - self.horizontal / 2 - self.vertical / 2 - Vec(
         0, 0, self.focal_length)
Exemple #8
0
 def scatter(self, r_in, rec, attenuation, scattered):
     reflected = r_in.direction.unit_vector().reflect(rec.normal)
     scattered.origin = rec.p
     scattered.direction = reflected
     attenuation.x = self.albedo.r
     attenuation.y = self.albedo.g
     attenuation.z = self.albedo.b
     return (Vec.dot(scattered.direction, rec.normal) > 0)
Exemple #9
0
def ray_color(r, world, depth):
    rec = HitRecord()
    if (depth <= 0):
        return Color(0, 0, 0)

    if world.hit(r, 0.001, inf, rec):
        scattered = Ray()
        attenuation = Color()
        if rec.material.scatter(r, rec, attenuation, scattered):
            return attenuation * ray_color(scattered, world, depth - 1)
            # experimenting with black and white
            #c = (color.x + color.y + color.z)/3
            #return Color(c,c,c)

        return Color(0, 0, 0)
    ud = r.direction.unit_vector()
    t = 0.5 * (ud.y + 1)
    return (1 - t) * Vec(1, 1, 1) + t * Vec(0.5, 0.7, 1.0)
Exemple #10
0
def color(ray, world, depth):
    hit_rec = HitRecord()
    if world.hit(ray, 0.001, float('inf'), hit_rec):
        scattered = Ray()
        attenuation = Vec()
        hit_mat = hit_rec.mat
        if depth < MAXIMUM_DEPTH and hit_mat.scatter(ray, hit_rec, attenuation,
                                                     scattered):
            return color(scattered, world, depth + 1).vec_mul(attenuation)
        else:
            return Vec()
    else:
        unit_dir = Vec.unit_vector(ray.direction)
        t = 0.5 * (unit_dir.y + 1)
        ti = 1 - t
        return Vec(ti * BG_COL_A.x + t * BG_COL_B.x,
                   ti * BG_COL_A.y + t * BG_COL_B.y,
                   ti * BG_COL_A.z + t * BG_COL_B.z)
Exemple #11
0
 def get_ray(self, s, t):
     if self.lens_radius > 0:
         rd = random_in_unit_disk().mul(self.lens_radius)
     else:
         rd = Vec()
     offset = (self.u * rd.x).add(self.v * rd.y)
     return Ray(
         self.origin + offset,
         offset.neg_add(self.lower_left + s * self.horizontal +
                        t * self.vertical - self.origin))
Exemple #12
0
 def scatter(self, r_in, rec, attenuation, scattered):
     scatter_direction = rec.normal + Vec.random_unit_vector()
     if scatter_direction.near_zero():
         scatter_direction = rec.normal
     scattered.origin = rec.p
     scattered.direction = scatter_direction
     attenuation.x = self.albedo.r
     attenuation.y = self.albedo.g
     attenuation.z = self.albedo.b
     return True
Exemple #13
0
def main():
    w = 3840
    h = 2160
    s = 5000
    start_time = time()

    spheres = HitableList()
    spheres.append(Sphere(Vec(0, 0, -1), 0.5, Lambertian(RGB(92, 184,
                                                             92))))  # Center
    spheres.append(
        Sphere(Vec(0, -100.5, -1), 100, Lambertian(RGB(217, 83, 79))))  # Base
    spheres.append(Sphere(Vec(1, 0, -1), 0.5, Metal(RGB(255, 238,
                                                        173))))  # Right
    spheres.append(Sphere(Vec(-1, 0, -1), 0.5, Dialectric(1.5)))  # Left

    lookfrom = Vec(0, 1, 4)
    lookat = Vec(0, 0, -1)
    dist_to_focus = (lookfrom - lookat).length()
    aperture = 0
    cam = Camera(w / h, 25, aperture, dist_to_focus, lookfrom, lookat)

    image = make_image(spheres, cam, w, h, s)

    normalize_color_range(image)
    write_image(image, w, h)
    print('Took %.2f seconds to process %d rays' %
          (time() - start_time, w * h * s))
Exemple #14
0
 def random_in_unit_sphere():
     p = Vec()
     while True:
         p.x = 2 * random() - 1
         p.y = 2 * random() - 1
         p.z = 2 * random() - 1
         if p.squared_length() < 1:
             break
     return p
Exemple #15
0
def worker(input, output, state):
    samples, width, height, cam, world = state
    range_samples = range(samples)
    range_width = range(width)
    for j in iter(input.get, 'STOP'):
        row = []
        for i in range_width:
            col = Vec(0, 0, 0)
            for s in range_samples:
                u = (i + random()) / width
                v = (j + random()) / height
                ray = cam.get_ray(u, v)
                col += color(ray, world, 0)
            col /= samples
            row.append(int(sqrt(col.x) * 255.99))
            row.append(int(sqrt(col.y) * 255.99))
            row.append(int(sqrt(col.z) * 255.99))
        output.put(RowResult(j, row))
Exemple #16
0
    def hit(self, r, t_min, t_max, rec):
        oc = r.origin - self.center
        a = r.direction.length_squared()
        half_b = Vec.dot(oc, r.direction)
        c = oc.length_squared() - self.radius * self.radius
        discriminant = half_b * half_b - a * c
        if (discriminant < 0):
            return False
        sqrtd = math.sqrt(discriminant)

        # find the nearest root that lies in the acceptable range
        root = (-half_b - sqrtd) / a
        if (root < t_min or t_max < root):
            root = (-half_b + sqrtd) / a
            if (root < t_min or t_max < root):
                return False
        rec.t = root
        rec.p = r.at(rec.t)
        outward_normal = (rec.p - self.center) / self.radius
        rec.set_face_normal(r, outward_normal)
        rec.material = self.material
        return True
Exemple #17
0
def make_image_sync(world, cam, width, height, samples):
    p = []
    range_width = range(width)
    range_samples = range(samples)
    for j in reversed(range(height)):
        row = []
        for i in range_width:
            col = Vec()
            for s in range_samples:
                u = (i + random()) / width
                v = (j + random()) / height
                ray = cam.get_ray(u, v)
                col.add(color(ray, world, 0))
            col.div(samples)
            row.append(int(sqrt(col.x) * 255.99))
            row.append(int(sqrt(col.y) * 255.99))
            row.append(int(sqrt(col.z) * 255.99))
        p.append(row)
    return p
Exemple #18
0
 def __init__(self, origin=Vec(0,0,0), direction=Vec(0,0,0)):
     self.origin = origin
     self.direction = direction
Exemple #19
0

def write_color(f, color, samples_per_pixel):
    scale = 1 / samples_per_pixel
    r, g, b = [
        clamp(math.sqrt(x * scale), 0, 0.999)
        for x in [color.r, color.g, color.b]
    ]
    f.write(f"{int(r*256)} {int(g*256)} {int(b*256)}\n")


world = World()
for x in range(130):
    world.add(
        Sphere(Vec(random() * 20 - 10,
                   random() * 20 - 10,
                   random() * -20), random(),
               Metal(Color(random(), random(), random()))))

#world.add(Sphere(Point3(0,0,-1), 0.5, Metal(Color(1,0.3,0.8))))
#world.add(Sphere(Point3(0,-100.5, -1), 100, Metal(Color(0.2,1,0.5))))


def ray_color(r, world, depth):
    rec = HitRecord()
    if (depth <= 0):
        return Color(0, 0, 0)

    if world.hit(r, 0.001, inf, rec):
        scattered = Ray()
        attenuation = Color()
Exemple #20
0
 def set_face_normal(self, r, outward_normal):
     self.front_face = Vec.dot(r.direction, outward_normal) < 0
     if self.front_face:
         self.normal = outward_normal
     else:
         self.normal = -outward_normal