def color_reflected_refracted(self, s, O, M, N, V, inside, bounces): to_O = vl.vnorm(O - M) reflect_color = np.zeros((3, 1)) refract_color = np.zeros((3, 1)) if (s.material.finish.transparent == False and s.material.finish.reflection == 0.) or bounces == self.num_bounces: return 0. reflect_amount = s.material.finish.reflection refract_amount = 0. if s.material.finish.transparent == True: reflect_amount = self.reflectance(s, N, V, inside) refract_amount = 1. - reflect_amount if np.any(reflect_amount > 0.): R = self.reflect(to_O, N) reflect_color = self.trace(s.geometry.intersection_point(M, N), R, bounces + 1) * reflect_amount if np.any(refract_amount > 0.): Rf = self.refract(s, V, N, inside) refract_color = refract_color + self.trace(s.geometry.intersection_point(M, -N), Rf, bounces + 1) * refract_amount return reflect_color + refract_color
def render(): img = misc.imread('examples/checkered.png')[:, :, :3] # img = misc.imread('examples/face.png')[:, :, :3] h, w, c = img.shape camera = Camera(500, 500) sphere = Sphere([0., 0., 0.], 1.) camera.translate([0, 0, -2]) t, m, n = sphere.intersection(camera.origin, camera.D) d_hat = vl.vnorm(m - sphere.center) d_x = d_hat[0:1] d_y = d_hat[1:2] d_z = d_hat[2:3] u = (0.5 + (np.arctan2(d_z, d_x) / (np.pi * 2))) v = 0.5 - (np.arcsin(d_y) / np.pi) img_out = img[(v * h - 1).astype(np.uint8), (u * w - 1).astype(np.uint8)].squeeze() mask = (t < global_config.MAX_DISTANCE).T plt.imshow((img_out * mask).reshape(camera.height, camera.width, 3)) plt.show() import ipdb ipdb.set_trace()
def refract(self, s, V, N, inside): n1 = np.where(inside, s.material.finish.ior, 1.) # TODO don't hardcode air as n1 n2 = np.where(inside, 1., s.material.finish.ior) n = n1 / n2 cos_i = -vl.vdot(N, V) sin_t2 = n * n * (1.0 - cos_i * cos_i) cos_t = np.sqrt(1. - sin_t2) return vl.vnorm(V * n + N * (n * cos_i - cos_t))
def color_specular(self, s, N, to_L, to_O, intensity): if s.material.finish.specular == 0.: return 0. else: R = self.reflect(to_L, N) specular_intensity = np.maximum(vl.vdot(to_O, R), 0.) specular_color = np.power(specular_intensity, 1./s.material.finish.roughness) * intensity * s.material.finish.specular if s.material.metallic == True: specular_color = specular_color * vl.vnorm(s.material.surface_color) return specular_color
def color_diffuse_specular(self, s, O, M, N, V): diffuse_color = np.zeros((3, 1)) specular_color = np.zeros((3, 1)) to_O = vl.vnorm(O - M) for light_source in self.scene.light_sources: if isinstance(light_source, LightSourcePoint): light_dir = light_source.center - M to_L = vl.vnorm(light_dir) r2 = vl.vabs(light_dir) intensity = light_source.emission_color * light_source.intensity / (4 * np.pi * r2) elif isinstance(light_source, LightSourceDirectional): to_L = -light_source.direction intensity = light_source.emission_color * light_source.intensity shadow_mask = self.shadow_mask(light_source, M, N, to_L) diffuse_color = diffuse_color + self.color_diffuse(s, N, to_L, intensity) * shadow_mask specular_color = specular_color + self.color_specular(s, N, to_L, to_O, intensity) * shadow_mask return diffuse_color + specular_color
def light(self, s, O, V, t, M, N, bounces): to_O = vl.vnorm(O - M) inside = (vl.vdot(V, N) > 0.) N_hat = np.where(inside, -N, N) ambient_color = self.color_ambient(s) diffuse_specular_color = self.color_diffuse_specular(s, O, M, N_hat, V) reflected_refracted_color = self.color_reflected_refracted(s, O, M, N_hat, V, inside, bounces) return ambient_color + diffuse_specular_color + reflected_refracted_color
def intersection(self, O, D): O_hat = vl.inverse_transform( self.S, vl.inverse_transform(self.R, vl.inverse_transform(self.T, O))) D_hat = vl.inverse_transform(self.S, vl.inverse_transform(self.R, D)) a = vl.vdot(D_hat, D_hat) b = 2 * vl.vdot(O_hat, D_hat) c = vl.vdot(O_hat, O_hat) - 1 disc = (b**2) - (4 * a * c) t0 = (-b - np.sqrt(np.maximum(disc, 0.))) / (2 * a) t1 = (-b + np.sqrt(np.maximum(disc, 0.))) / (2 * a) t = np.where((t0 > 0) & (t0 < t1), t0, t1) pred = (disc > 0.) & (t > 0.) t_out = np.where(pred, t, global_config.MAX_DISTANCE) M = (O_hat + D_hat * t_out) M_out = vl.transform(self.T, vl.transform(self.R, vl.transform(self.S, M))) N_out = vl.vnorm(vl.transform(self.R, vl.inverse_transform(self.S, M))) return t_out, M_out, N_out
def intersection(self, O, D): O_hat = vl.inverse_transform( self.S, vl.inverse_transform(self.R, vl.inverse_transform(self.T, O))) D_hat = vl.inverse_transform(self.S, vl.inverse_transform(self.R, D)) xy_mask = np.array([1., 1., 0.]).reshape(-1, 1) O_xy = O_hat * xy_mask D_xy = D_hat * xy_mask a = vl.vdot(D_xy, D_xy) b = 2 * vl.vdot(D_xy, O_xy) c = vl.vdot(O_xy, O_xy) - 1 disc = (b**2) - (4 * a * c) t0 = (-b - np.sqrt(np.maximum(disc, 0.))) / (2 * a) t1 = (-b + np.sqrt(np.maximum(disc, 0.))) / (2 * a) zo = O_hat[2:3] zd = D_hat[2:3] z0 = (zo + zd * t0) z1 = (zo + zd * t1) z0_mask = (t0 > 0) & (z0 <= self.z_max) & (z0 >= self.z_min) & (disc > 0.) z1_mask = (t1 > 0) & (z1 <= self.z_max) & (z1 >= self.z_min) & (disc > 0.) # # Compute Cylinder Intersections t_cand0 = np.where(z0_mask, t0, global_config.MAX_DISTANCE) t_cand1 = np.where(z1_mask, t1, global_config.MAX_DISTANCE) t_cand_cyl = np.min(np.array([t_cand0, t_cand1]), axis=0) # # Compute Endcap Cylinder Intersections if self.closed is True: t3 = (self.z_min - zo) / zd t4 = (self.z_max - zo) / zd P_front = (O_xy + D_xy * t3) P_back = (O_xy + D_xy * t4) front_cap_hit_mask = (vl.vdot(P_front, P_front) <= 1.) back_cap_hit_mask = (vl.vdot(P_back, P_back) <= 1.) hit_mask = (z0_mask | z1_mask) t_front_cap = front_cap_hit_mask * t3 t_back_cap = back_cap_hit_mask * t4 t_side = t_cand_cyl t_front_cap[t_front_cap <= 0.] = global_config.MAX_DISTANCE t_back_cap[t_back_cap <= 0.] = global_config.MAX_DISTANCE t_side[t_side <= 0.] = global_config.MAX_DISTANCE t_out = np.min([t_side, t_front_cap, t_back_cap], axis=0) t_arg_out = np.argmin([t_side, t_front_cap, t_back_cap], axis=0) M_out = O_hat + D_hat * t_out normal_cyl = hit_mask * (M_out * xy_mask) normal_front_cap = front_cap_hit_mask * np.array( [0, 0, -1]).reshape(-1, 1) normal_back_cap = back_cap_hit_mask * np.array([0, 0, 1]).reshape( -1, 1) normals = np.sum([ normal_cyl * (t_arg_out == 0), normal_front_cap * (t_arg_out == 1), normal_back_cap * (t_arg_out == 2) ], axis=0) M_out = vl.transform( self.T, vl.transform(self.R, vl.transform(self.S, M_out))) N_out = vl.vnorm( vl.transform(self.R, vl.inverse_transform(self.S, normals))) return t_out, M_out, N_out else: t_out = t_cand_cyl M = (O_hat + D_hat * t_out) M_out = vl.transform(self.T, vl.transform(self.R, vl.transform(self.S, M))) N_out = vl.vnorm( vl.transform(self.R, vl.inverse_transform(self.S, M * xy_mask))) return t_out, M_out, N_out
def __init__(self, direction, emission_color=np.ones((3, 1)), intensity=1.): super(LightSourceDirectional, self).__init__(emission_color, intensity) self.direction = vl.vnorm(np.reshape(direction, (3, 1)))
def get_normal(self): return -vl.vnorm(vl.triangle_normal(self.vertices))
def reflect(self, V, N): return vl.vnorm(N * 2 * vl.vdot(V, N) - V)
def D(self): return vl.vnorm(self.screen - self.origin)
def intersection(self, O, D): O_hat = vl.inverse_transform( self.S, vl.inverse_transform(self.R, vl.inverse_transform(self.T, O))) D_hat = vl.inverse_transform(self.S, vl.inverse_transform(self.R, D)) xy_mask = np.array([1., 1., 0.]).reshape(-1, 1) z_mask = np.array([0., 0., 1.]).reshape(-1, 1) O_xy = O_hat * xy_mask O_z = O_hat * z_mask D_xy = D_hat * xy_mask D_z = D_hat * z_mask a = vl.vdot(D_xy, D_xy) - vl.vdot(D_z, D_z) b = (2 * vl.vdot(D_xy, O_xy)) - (2 * vl.vdot(D_z, O_z)) c = vl.vdot(O_xy, O_xy) - vl.vdot(O_z, O_z) disc = (b**2) - (4 * a * c) t0 = (-b - np.sqrt(np.maximum(disc, 0.))) / (2 * a) t1 = (-b + np.sqrt(np.maximum(disc, 0.))) / (2 * a) zo = O_hat[2:3] zd = D_hat[2:3] z0 = (zo + zd * t0) z1 = (zo + zd * t1) z0_mask = (t0 > 0) & (z0 <= self.z_max) & (z0 >= self.z_min) & (disc > 0.) z1_mask = (t1 > 0) & (z1 <= self.z_max) & (z1 >= self.z_min) & (disc > 0.) # Compute Cone Intersections t_cand0 = np.where(z0_mask, t0, global_config.MAX_DISTANCE) t_cand1 = np.where(z1_mask, t1, global_config.MAX_DISTANCE) t_cand_cone = np.min(np.array([t_cand0, t_cand1]), axis=0) # Compute Endcap Cone Intersections if self.closed is True: t4 = (self.z_max - zo) / zd P_back = (O_xy + D_xy * t4) back_cap_hit_mask = (vl.vdot(P_back, P_back) <= 1.) hit_mask = (z0_mask | z1_mask) t_side = t_cand_cone t_back_cap = back_cap_hit_mask * t4 t_back_cap[t_back_cap <= 0.] = global_config.MAX_DISTANCE t_side[t_side <= 0.] = global_config.MAX_DISTANCE t_out = np.min([t_side, t_back_cap], axis=0) t_arg_out = np.argmin([t_side, t_back_cap], axis=0) M_out = O_hat + D_hat * t_out M_norm = (M_out * xy_mask) M_norm[2, :] = -1. normal_cone = M_norm normal_back_cap = back_cap_hit_mask * np.array([0, 0, 1]).reshape( -1, 1) normals = np.sum([ normal_cone * (t_arg_out == 0), normal_back_cap * (t_arg_out == 1) ], axis=0) M_out = vl.transform( self.T, vl.transform(self.R, vl.transform(self.S, M_out))) N_out = vl.vnorm( vl.transform(self.R, vl.inverse_transform(self.S, normals))) return t_out, M_out, N_out else: t_out = t_cand_cone M = (O_hat + D_hat * t_out) M_norm = M * xy_mask M_norm[2, :] = -1. M_out = vl.transform(self.T, vl.transform(self.R, vl.transform(self.S, M))) N_out = vl.vnorm( vl.transform(self.R, vl.inverse_transform(self.S, M_norm))) return t_out, M_out, N_out
def normal_to(self, M): return vl.vnorm( vl.inverse_transform(self.S, vl.inverse_transform(self.T, M)))