def scatter(self, r_in, rec): reflected = reflect(r_in.direction(), rec.record[2]) attenuation = vec3(1.0, 1.0, 1.0) if (vec3.dot(r_in.direction(), rec.record[2]) > 0): outworld_normal = -rec.record[2] ni_over_nt = self.ref_idx cosine = self.ref_idx * vec3.dot(r_in.direction(), rec.record[2]) / r_in.direction().length() else: outworld_normal = rec.record[2] ni_over_nt = 1.0 / self.ref_idx cosine = -vec3.dot(r_in.direction(), rec.record[2]) / r_in.direction().length() isok, refracted = refract(r_in.direction(), outworld_normal, ni_over_nt) if isok: reflect_prob = schlick(cosine, self.ref_idx) else: reflect_prob = 1.0 if random.random() < reflect_prob: scattered = ray(rec.record[1], reflected) else: scattered = ray(rec.record[1], refracted) return True, scattered, attenuation
def hit_sphere(center, radius, r): oc = r.origin - center a = vec3.dot(r.direction, r.direction) b = 2.0 * vec3.dot(oc, r.direction) c = vec3.dot(oc, oc) - radius * radius discriminat = b * b - 4 * a * c if discriminat < 0: return -1.0 else: return (-b - math.sqrt(discriminat)) / (2.0 * a)
def refract(v, n, ni_over_nt): uv = vec3.unit_vector(v) dt = vec3.dot(uv, n) discriminant = 1.0 - ni_over_nt*ni_over_nt*(1-dt*dt) refracted = vec3(0, 0, 0) if discriminant > 0: refracted = ni_over_nt*(uv - n*dt) - n*math.sqrt(discriminant) return True, refracted else: return False, refracted
def hit(self, r, t_min, t_max, rec): oc = r.origin() - self.center a = vec3.dot(r.direction(), r.direction()) b = vec3.dot(oc, r.direction()) c = vec3.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.record[0] = temp rec.record[1] = r.point_at_parameter(rec.record[0]) rec.record[2] = (rec.record[1] - self.center) / self.radius rec.record[3] = self.mat return True temp = (-b + math.sqrt(discriminant)) / a if temp < t_max and temp > t_min: rec.record[0] = temp rec.record[1] = r.point_at_parameter(rec.record[0]) rec.record[2] = (rec.record[1] - self.center) / self.radius rec.record[3] = self.mat return True return False
def random_in_unit_disk(): while True: p = 2.0 * vec3(random.random(), random.random(), 0) - vec3(1, 1, 0) if vec3.dot(p, p) < 1: break return p
def reflect(v, n): if isinstance(v, vec3) and isinstance(n, vec3): return v - 2*vec3.dot(v, n)*n else: return NotImplemented
def scatter(self, r_in, rec): reflected = reflect(vec3.unit_vector(r_in.direction()), rec.record[2]) scattered = ray(rec.record[1], reflected + self.fuzz*random_in_unit_sphere()) isok = (vec3.dot(scattered.direction(), rec.record[2]) > 0) return isok, scattered, self.albedo