def scatter(self, ray_in: Ray, hit_record: hit_record): outward_normal = Vector3(1, 1, 1) reflected = ray_in.direction().reflect(hit_record.normal) ni_over_nt = 0 attenuation = Vector3(1, 1, 1) scattered = Vector3(0, 0, 0) reflect_prob = 0 cosine = 0 if (ray_in.direction().dot(hit_record.normal) > 0): outward_normal = Vector3(0, 0, 0) - hit_record.normal ni_over_nt = self.ref_idx cosine = self.ref_idx * ray_in.direction().dot( hit_record.normal) / ray_in.direction().length() else: outward_normal = hit_record.normal ni_over_nt = 1 / self.ref_idx cosine = -ray_in.direction().dot( hit_record.normal) / ray_in.direction().length() is_scattered, refracted = refract(ray_in.direction(), outward_normal, ni_over_nt) if (is_scattered): reflect_prob = schlick(cosine, self.ref_idx) else: scattered = Ray(hit_record.p, reflected) reflect_prob = 1.0 if (random.uniform(0, 1) < reflect_prob): scattered = Ray(hit_record.p, reflected) else: scattered = Ray(hit_record.p, refracted) return (True, scattered, attenuation)
def random_in_unit_disk(): p = Vector3(0,0,0) while (p.dot(p) >= 1.0): p = Vector3(random.uniform(0,1), random.uniform(0,1), 0).scalar_mul(2.0) - Vector3(1,1,0) return p
def random_in_unit_sphere(): p = Vector3(random.uniform(0, 1), random.uniform(0, 1), random.uniform( 0, 1)).scalar_mul(2.0) - Vector3(1, 1, 1) while (p.squared_length() >= 1.0): p = Vector3(random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1)).scalar_mul(2.0) - Vector3(1, 1, 1) return p
def refract(v: Vector3, n: Vector3, ni_over_nt: float): uv = v.normalize() dt = uv.dot(n) discriminant = 1.0 - ni_over_nt * ni_over_nt * (1 - dt * dt) if (discriminant > 0): refracted = (uv - n.scalar_mul(dt)).scalar_mul(ni_over_nt) - n.scalar_mul( math.sqrt(discriminant)) return (True, refracted) return (False, Vector3(0, 0, 0))
def hit(self, ray: Ray, t_min: float, t_max: float): temp_rec = hit_record(0, Vector3(0, 0, 0), Vector3(0, 0, 0), Material()) hit_anything = False closest_so_far = t_max for item in self.list: if (item.hit(ray, t_min, closest_so_far, temp_rec)): hit_anything = True closest_so_far = temp_rec.t temp_rec.material = item.material return (hit_anything, temp_rec)
def __init__(self, lookfrom: Vector3, lookat: Vector3, vup: Vector3, fov, aspect, aperture, focus_dist): theta = fov * (3.145 / 180.0) half_height = math.tan(theta/2.0) half_width = aspect * half_height self.origin = lookfrom self.w = (lookfrom - lookat).normalize() self.u = vup.cross(self.w).normalize() self.v = self.w.cross(self.u) self.lower_left_corner = self.origin - self.u.scalar_mul(half_width) - self.v.scalar_mul(half_height * focus_dist) - self.w.scalar_mul(focus_dist) self.horizontal = self.u.scalar_mul(2 * half_width * focus_dist) self.vertical = self.v.scalar_mul(2 * half_height * focus_dist) self.lens_radius = 0.0
def hit(self, ray: Ray, t_min: float, t_max: float, rec: hit_record): oc = ray.origin() - self.center a = Vector3.dot(ray.direction(), ray.direction()) b = Vector3.dot(oc, ray.direction()) c = Vector3.dot(oc, oc) - self.radius * self.radius discriminant = b * b - a * c if (discriminant > 0): temp = (-b - math.sqrt(discriminant)) / a if (temp < t_max and temp > t_min): rec.t = temp rec.p = ray.point_at_parameter(rec.t) rec.normal = (rec.p - self.center).scalar_div(self.radius) return True temp = (-b + math.sqrt(discriminant)) / a if (temp < t_max and temp > t_min): rec.t = temp rec.p = ray.point_at_parameter(rec.t) rec.normal = (rec.p - self.center).scalar_div(self.radius) return True return False
def scatter(self, ray_in: Ray, rec): return (False, Ray(Vector3(0, 0, 0), Vector3(0, 0, 0)))