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
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
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
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)
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
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
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
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