def build_from_w(self, n: Vector3): self._w = Vector3.normalize(n) if math.fabs(self._w.x()) > 0.9: a = Vector3(0, 1, 0) else: a = Vector3(1, 0, 0) self._v = Vector3.normalize(Vector3.cross(self._w, a)) self._u = Vector3.cross(self._w, self._v)
def calculate_ray_color(self, ray: Ray, depth: float): has_hit, hit_record = self._bvh_world.hit(ray=ray, t_min=0.001, t_max=float('inf')) if has_hit is True: scattered, attenuation = hit_record.material.scatter( ray_incident=ray, hit_record=hit_record) emitted = hit_record.material.emitted(u=hit_record.u, v=hit_record.v, p=hit_record.hit_point) if depth < 50 and scattered is not None: return emitted + attenuation * self.calculate_ray_color( ray=scattered, depth=depth + 1) else: return emitted else: # Ambient Color # return Vector3(0.0, 0.0, 0.0) ray_direction = Vector3.normalize(ray.direction) t = 0.5 * (ray_direction.y() + 1.0) return (1.0 - t) * Vector3(0.2, 0.2, 0.2) + t * Vector3( 0.5, 0.7, 1.0)
def perlin_generate(self): p = list() for i in range(256): p.append( Vector3.normalize( Vector3(-1 + 2 * random.random(), -1 + 2 * random.random(), -1 + 2 * random.random()))) return p
def __init__(self, lookfrom:'Vector3', lookat:'Vector3', vectorup:'Vector3', vfov:'float', aspect:'float', aperture:'float', focus_dist:'float', t0:float, t1:float): theta = vfov * math.pi / 180 # vfov to radians half_height = math.tan(theta / 2) # h = tan(theta / 2) half_width = half_height * aspect self._lens_radius = aperture / 2 self._time0 = t0 self._time1 = t1 self._camera_origin = lookfrom w = Vector3.normalize(lookfrom - lookat) u = Vector3.normalize(Vector3.cross(vectorup, w)) v = Vector3.cross(w, u) self._lower_left_corner = self._camera_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
def get_sphere_uv(self, p: Vector3) -> (float, float): """Get the uv coordinates of a point in the sphere""" d = Vector3.normalize(p - self._center) phi = math.atan2(d.z(), d.x()) / (2 * math.pi) u = phi + 0.5 v = 0.5 - (math.asin(d.y()) / math.pi) return u, v
def scatter(self, ray_incident: Ray, hit_record: HitRecord): reflected_vector = Vector3.reflect( Vector3.normalize(ray_incident.direction), hit_record.hit_point_normal) attenuation = Vector3(1.0, 1.0, 1.0) refracted_vector = Vector3.refract(incident=ray_incident.direction, normal=hit_record.hit_point_normal, n1=1.0, n2=self._refraction_index) reflect_probability = self.schlick(incident=ray_incident.direction, normal=hit_record.hit_point_normal, n1=1.0, n2=self._refraction_index) if random.random() < reflect_probability: scattered = Ray(hit_record.hit_point, reflected_vector, ray_incident.time) else: scattered = Ray(hit_record.hit_point, refracted_vector, ray_incident.time) return scattered, attenuation
def value(self, direction: Vector3) -> float: cosine = Vector3.dot(Vector3.normalize(direction), self._uvw.w()) if cosine > 0: return cosine / math.pi else: return 0