def __init__(self, lookfrom: vector.Vec3, lookat: vector.Vec3, vup: vector.Vec3, vfov: float, aspect_ratio: float, aperture: float, focus_dist: float): self.origin = lookfrom self.lens_radius = aperture / 2 theta = util.degrees_to_radians(vfov) half_height = math.tan(theta / 2) half_width = aspect_ratio * half_height self.w1 = vector.unit_vector(lookfrom - lookat) self.u1 = vector.unit_vector(vector.cross(vup, self.w1)) self.v1 = vector.cross(self.w1, self.u1) self.lower_left_corner = self.origin - self.u1.times( half_width * focus_dist) - self.v1.times( half_height * focus_dist) - self.w1.times(focus_dist) self.horizontal = self.u1.times(half_width * 2 * focus_dist) self.vertical = self.v1.times(half_height * 2 * focus_dist) self.vfov = vfov self.aspect_ratio = aspect_ratio
def angle_between(self, a, b): # based on http://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python """ Returns the angle in radians between vectors 'v1' and 'v2':: """ v0 = np.array([a.slope_v.x, a.slope_v.y]) v1 = np.array([b.slope_v.x, b.slope_v.y]) v0_u = unit_vector(v0) v1_u = unit_vector(v1) angle = np.arccos(np.dot(v0_u, v1_u)) if np.isnan(angle): if (v0_u == v1_u).all(): return 0.0 else: return 360.0 return np.degrees(angle)
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord): attenuation = vector.Vec3(1.0, 1.0, 1.0) etai_over_etat = self.ref_idx if hit_record.front_face: etai_over_etat = 1.0 / self.ref_idx unit_direction = vector.unit_vector(ray_in.direction) cos_theta = min(vector.dot(-unit_direction, hit_record.normal), 1.0) sin_theta = math.sqrt(1.0 - cos_theta*cos_theta) if etai_over_etat * sin_theta > 1.0: reflected = vector.reflect(unit_direction, hit_record.normal) scattered = vector.Ray(hit_record.position, reflected) return True, attenuation, scattered reflect_prob = vector.schlick(cos_theta, etai_over_etat) if util.random_double() < reflect_prob: reflected = vector.reflect(unit_direction, hit_record.normal) scattered = vector.Ray(hit_record.position, reflected) return True, attenuation, scattered refracted = vector.refract(unit_direction, hit_record.normal, etai_over_etat) scattered = vector.Ray(hit_record.position, refracted) return True, attenuation, scattered
def raytrace(r, scene, depth): # Determine the closest hits distances = [s.intersect(r, 0.001, 1.0e39) for s in scene] nearest = ft.reduce(np.minimum, distances) # Ambient color = rgb(0.0, 0.0, 0.0) unit_dir = unit_vector(r.direction()) t = (unit_dir.y + 1.0) * 0.5 # bgc = (vec3(1.0, 1.0, 1.0)*(1.0 - t) + vec3(0.5, 0.7, 1.0)*t) bgc = vec3(0.5, 0.7, 1.0) * t for (s, d) in zip(scene, distances): hit = (nearest != 1.0e39) & (d == nearest) print("depth: %s | Radius: %s | Shape: %s" % (depth, s.radius, hit.shape)) time.sleep(0.1) if np.any(hit) and depth < 5: dc = np.extract(hit, d) oc = r.origin().extract(hit) dirc = r.direction().extract(hit) er = ray(oc, dirc) p = er.point_at_parameter(dc) N = (p - s.center) / vec3(s.radius, s.radius, s.radius) shader = s.material() scattered = shader.scatter(er, p, N) cc = raytrace(scattered, scene, depth + 1) * shader.albedo # cc = vec3(shader.albedo, shader.albedo, shader.albedo) color += cc.place2(hit, bgc) return color
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord): reflected = vector.reflect(vector.unit_vector(ray_in.direction), hit_record.normal) scattered = vector.Ray(hit_record.position, reflected + vector.random_in_unit_sphere().times(self.fuzz)) didscatter = (vector.dot(scattered.direction, hit_record.normal) > 0) return didscatter, self.color, scattered
def angle_x_axis(self): # based on http://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python """ Returns the angle in radians between vectors 'v1' and 'v2':: >>> angle_between((1, 0, 0), (0, 1, 0)) 1.5707963267948966 >>> angle_between((1, 0, 0), (1, 0, 0)) 0.0 >>> angle_between((1, 0, 0), (-1, 0, 0)) 3.141592653589793 """ v0 = np.array([self.slope_v.x, self.slope_v.y]) v1 = np.array([1, 0]) v0_u = unit_vector(v0) v1_u = unit_vector(v1) angle = np.arccos(np.dot(v0_u, v1_u)) if np.isnan(angle): if (v0_u == v1_u).all(): return 0.0 else: return 360.0 return np.degrees(angle)
def angle_between(self, a, b): # based on http://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python """ Returns the angle in radians between vectors 'v1' and 'v2':: angle_between((1, 0, 0), (0, 1, 0)) 1.5707963267948966 angle_between((1, 0, 0), (1, 0, 0)) 0.0 angle_between((1, 0, 0), (-1, 0, 0)) 3.141592653589793 """ v0 = a[1] - a[0] v1 = b[1] - b[0] v0_u = unit_vector(v0) v1_u = unit_vector(v1) angle = np.arccos(np.dot(v0_u, v1_u)) if np.isnan(angle): if (v0_u == v1_u).all(): return 0.0 else: return 360 return np.degrees(angle)
def raytrace_OLD(r, scene): hitpts = hit_sphere(vec3(0.0, 0.0, -1.0), 0.4, r) m = np.copy(hitpts) unit_direction = unit_vector(r.direction()) t = 0.5 * (unit_direction.y + 1.0) mask = np.where(m > 0.0, 0, 1) N = (r.point_at_parameter(t) - vec3(0.0, 0.0, -1.0)) * (1.0 / 0.4) Nc = (vec3(N.x + 1, N.y + 1, N.z + 1) * 0.5) color = (vec3(1.0, 1.0, 1.0) * (1.0 - t) + vec3(0.5, 0.7, 1.0) * t) * mask + (Nc * (1 - mask)) return (color)
def ray_color(ray: vector.Ray, world: hittable.Hittable, depth): if depth <= 0: return vector.Vec3(0.0, 0.0, 0.0) did_hit, hit_rec = world.hit(ray, 0.001, util.INFINITY) if did_hit: tempmaterial = hit_rec.material didscatter, albedo, scattered = tempmaterial.scatter(ray, hit_rec) if didscatter: return albedo * ray_color(scattered, world, depth - 1) return vector.Vec3(0, 0, 0) unit_dir = vector.unit_vector(ray.direction) t = (unit_dir.y + 1.0) * 0.5 return vector.Vec3(1.0, 1.0, 1.0).times(1.0 - t) + vector.Vec3( 0.5, 0.7, 1.0).times(t)
def scatter(self, r_in, P, N): reflected = reflect(unit_vector(r_in.direction()), N) scattered = ray(P, reflected) # isReflected = (N.dot(scattered.direction()) > 0) # return np.where(isReflected, True, False) return scattered