def hit(self, r: Ray, t_min: float, t_max: float) -> Optional[HitRecord]: oc: Vec3 = r.origin() - self.center(r.time()) a: float = r.direction().length_squared() half_b: float = oc @ r.direction() c: float = oc.length_squared() - self.radius**2 discriminant: float = half_b**2 - a * c if discriminant > 0: root: float = np.sqrt(discriminant) t_0: float = (-half_b - root) / a t_1: float = (-half_b + root) / a if t_min < t_0 < t_max: t = t_0 elif t_min < t_1 < t_max: t = t_1 else: return None point: Point3 = r.at(t) outward_normal: Vec3 = ((point - self.center(r.time())) / self.radius) rec = HitRecord(point, t, self.material) rec.set_face_normal(r, outward_normal) return rec return None
def hit(self, r: Ray, t_min: float, t_max: float) -> Optional[HitRecord]: origin = r.origin().copy() direction = r.direction().copy() origin[0] = self.cos_theta * r.origin()[0] - self.sin_theta * r.origin( )[2] origin[2] = self.sin_theta * r.origin()[0] + self.cos_theta * r.origin( )[2] direction[0] = \ self.cos_theta*r.direction()[0] - self.sin_theta*r.direction()[2] direction[2] = \ self.sin_theta*r.direction()[0] + self.cos_theta*r.direction()[2] rotated_r = Ray(origin, direction, r.time()) rec = self.obj.hit(rotated_r, t_min, t_max) if rec is None: return None p = rec.p.copy() normal = rec.normal.copy() p[0] = self.cos_theta * rec.p[0] + self.sin_theta * rec.p[2] p[2] = -self.sin_theta * rec.p[0] + self.cos_theta * rec.p[2] normal[0] = \ self.cos_theta*rec.normal[0] + self.sin_theta*rec.normal[2] normal[2] = \ -self.sin_theta*rec.normal[0] + self.cos_theta*rec.normal[2] rec.p = p rec.set_face_normal(rotated_r, normal) return rec
def scatter(self, r_in: Ray, rec: HitRecord) \ -> Optional[Tuple[Ray, Color]]: if not rec.front_face: return None scatter_direction: Vec3 = rec.normal + Vec3.random_unit_vector() scattered = Ray(rec.p, scatter_direction, r_in.time()) attenuation = self.albedo.value(rec.u, rec.v, rec.p) return scattered, attenuation
def hit(self, r: Ray, t_min: float, t_max: float) -> Optional[HitRecord]: # remove the offset to hit the real object moved_r = Ray(r.origin() - self.offset, r.direction(), r.time()) rec = self.obj.hit(moved_r, t_min, t_max) if rec is None: return None # add the offset back to simulate the move rec.p += self.offset rec.set_face_normal(moved_r, rec.normal) return rec
def scatter(self, r_in: Ray, rec: HitRecord) \ -> Optional[Tuple[Ray, Color]]: scattered = Ray(rec.p, Vec3.random_in_unit_sphere(), r_in.time()) attenuation = self.albedo.value(rec.u, rec.v, rec.p) return scattered, attenuation