def ray_color(r: RayList, world: HittableList, depth: int) \ -> Tuple[Optional[RayList], Optional[Vec3List], Vec3List]: length = len(r) if not r.direction().e.any(): return None, None, Vec3List.new_zero(length) # Calculate object hits rec_list: HitRecordList = world.hit(r, 0.001, cp.inf) # Useful empty arrays empty_vec3list = Vec3List.new_zero(length) empty_array_float = cp.zeros(length, cp.float32) empty_array_bool = cp.zeros(length, cp.bool) empty_array_int = cp.zeros(length, cp.int32) # Background / Sky unit_direction = r.direction().unit_vector() sky_condition = Vec3List.from_array((unit_direction.length() > 0) & (rec_list.material == 0)) t = (unit_direction.y() + 1) * 0.5 blue_bg = (Vec3List.from_vec3(Color(1, 1, 1), length).mul_ndarray(1 - t) + Vec3List.from_vec3(Color(0.5, 0.7, 1), length).mul_ndarray(t)) result_bg = Vec3List(cp.where(sky_condition.e, blue_bg.e, empty_vec3list.e)) if depth <= 1: return None, None, result_bg # Material scatter calculations materials: Dict[int, Material] = world.get_materials() scattered_list = RayList.new_zero(length) attenuation_list = Vec3List.new_zero(length) for mat_idx in materials: mat_condition = (rec_list.material == mat_idx) mat_condition_3 = Vec3List.from_array(mat_condition) if not mat_condition.any(): continue ray = RayList( Vec3List(cp.where(mat_condition_3.e, r.orig.e, empty_vec3list.e)), Vec3List(cp.where(mat_condition_3.e, r.dir.e, empty_vec3list.e))) rec = HitRecordList( Vec3List( cp.where(mat_condition_3.e, rec_list.p.e, empty_vec3list.e)), cp.where(mat_condition, rec_list.t, empty_array_float), cp.where(mat_condition, rec_list.material, empty_array_int), Vec3List( cp.where(mat_condition_3.e, rec_list.normal.e, empty_vec3list.e)), cp.where(mat_condition, rec_list.front_face, empty_array_bool)) ray, rec, idx_list = compress(ray, rec) scattered, attenuation = materials[mat_idx].scatter(ray, rec) scattered, attenuation = decompress(scattered, attenuation, idx_list, length) scattered_list += scattered attenuation_list += attenuation return scattered_list, attenuation_list, result_bg
def ray_color(r, world, depth): length = len(r) if not r.direction().e.any(): return None, None, Vec3List.new_zero(length) rec_list = world.hit(r, 0.001, cp.inf) empty_vec3list = Vec3List.new_zero(length) empty_array_float = cp.zeros(length, cp.float32) empty_array_bool = cp.zeros(length, cp.bool) empty_array_int = cp.zeros(length, cp.int32) unit_direction = r.direction().unit_vector() sky_condition = Vec3List.from_array((unit_direction.length() > 0) & (rec_list.material == 0)) t = (unit_direction.y() + 1) * 0.5 blue_bg = (Vec3List.from_vec3(Color(1, 1, 1), length).mul_ndarray(1 - t) + Vec3List.from_vec3(Color(0.5, 0.7, 1), length).mul_ndarray(t)) result_bg = Vec3List(cp.where(sky_condition.e, blue_bg.e, empty_vec3list.e)) if depth <= 1: return None, None, result_bg materials = world.get_materials() scattered_list = RayList.new_zero(length) attenuation_list = Vec3List.new_zero(length) for mat_idx in materials: mat_condition = (rec_list.material == mat_idx) mat_condition_3 = Vec3List.from_array(mat_condition) if not mat_condition.any(): continue ray = RayList( Vec3List( cp.where(mat_condition_3.e, r.origin().e, empty_vec3list.e)), Vec3List( cp.where(mat_condition_3.e, r.direction().e, empty_vec3list.e))) rec = HitRecordList( Vec3List( cp.where(mat_condition_3.e, rec_list.p.e, empty_vec3list.e)), cp.where(mat_condition, rec_list.t, empty_array_float), cp.where(mat_condition, rec_list.material, empty_array_int), Vec3List( cp.where(mat_condition_3.e, rec_list.normal.e, empty_vec3list.e)), cp.where(mat_condition, rec_list.front_face, empty_array_bool)) ray, rec, idx_list = compress(ray, rec) scattered, attenuation = materials[mat_idx].scatter(ray, rec) scattered, attenuation = decompress(scattered, attenuation, idx_list, length) scattered_list += scattered attenuation_list += attenuation return scattered_list, attenuation_list, result_bg
def __init__(self, point: Vec3List, t: cp.ndarray, mat: cp.ndarray, normal: Vec3List = Vec3List.new_zero(0), front_face: cp.ndarray = cp.array([])) -> None: self.p = point self.t = t self.material = mat self.normal = normal self.front_face = front_face
def __init__(self, point, t, mat, normal=Vec3List.new_zero(0), front_face=cp.array([])): self.p = point self.t = t self.material = mat self.normal = normal self.front_face = front_face
def decompress(r, a, idx, length): if idx is None: return r, a old_idx = cp.arange(len(idx)) new_r = RayList.new_zero(length) new_r.origin().e[idx] = r.origin().e[old_idx] new_r.direction().e[idx] = r.direction().e[old_idx] new_a = Vec3List.new_zero(length) new_a.e[idx] = a.e[old_idx] return new_r, new_a
def decompress(r: RayList, a: Vec3List, idx: Optional[np.ndarray], length: int) -> Tuple[RayList, Vec3List]: if idx is None: return r, a old_idx = np.arange(len(idx)) new_r = RayList.new_zero(length) new_r.orig.e[idx] = r.orig.e[old_idx] new_r.dir.e[idx] = r.dir.e[old_idx] new_a = Vec3List.new_zero(length) new_a.e[idx] = a.e[old_idx] return new_r, new_a
def new_zero(length): return RayList(Vec3List.new_zero(length), Vec3List.new_zero(length))
def new_zero(length: int) -> RayList: return RayList(Vec3List.new_zero(length), Vec3List.new_zero(length))
def ray_color(r: RayList, world: HittableList, depth: int) -> Vec3List: length = len(r) if not r.direction().e.any(): return Vec3List.new_zero(length) # Calculate object hits rec_list: HitRecordList = world.hit(r, 0.001, np.inf) # Useful empty arrays empty_vec3list = Vec3List.new_zero(length) empty_array_float = np.zeros(length, np.float32) empty_array_bool = np.zeros(length, np.bool) empty_array_int = np.zeros(length, np.int32) # Background / Sky unit_direction = r.direction().unit_vector() sky_condition = Vec3List.from_array((unit_direction.length() > 0) & (rec_list.material == 0)) t = (unit_direction.y() + 1) * 0.5 blue_bg = (Vec3List.from_vec3(Color(1, 1, 1), length).mul_ndarray(1 - t) + Vec3List.from_vec3(Color(0.5, 0.7, 1), length).mul_ndarray(t)) result_bg = Vec3List(np.where(sky_condition.e, blue_bg.e, empty_vec3list.e)) if depth <= 1: return result_bg # Per-material preparations materials: Dict[int, Material] = world.get_materials() material_dict: Dict[int, Tuple[RayList, HitRecordList]] = dict() for mat_idx in materials: mat_condition = (rec_list.material == mat_idx) mat_condition_3 = Vec3List.from_array(mat_condition) if not mat_condition.any(): continue raylist_temp = RayList( Vec3List(np.where(mat_condition_3.e, r.orig.e, empty_vec3list.e)), Vec3List(np.where(mat_condition_3.e, r.dir.e, empty_vec3list.e))) reclist_temp = HitRecordList( Vec3List( np.where(mat_condition_3.e, rec_list.p.e, empty_vec3list.e)), np.where(mat_condition, rec_list.t, empty_array_float), np.where(mat_condition, rec_list.material, empty_array_int), Vec3List( np.where(mat_condition_3.e, rec_list.normal.e, empty_vec3list.e)), np.where(mat_condition, rec_list.front_face, empty_array_bool)) material_dict[mat_idx] = raylist_temp, reclist_temp # Material scatter calculations scattered_list = RayList.new_zero(length) attenuation_list = Vec3List.new_zero(length) for key in material_dict: ray, rec = material_dict[key] ray, rec, idx_list = compress(ray, rec) scattered, attenuation = materials[key].scatter(ray, rec) scattered, attenuation = decompress(scattered, attenuation, idx_list, length) scattered_list += scattered attenuation_list += attenuation result_hittable = (attenuation_list * ray_color(scattered_list, world, depth - 1)) return result_hittable + result_bg