def intersection(self, O, D): D_hat = vl.vdot(self.normal, self.vertices[:, :1] - O) num = D_hat den = vl.vdot(self.normal, D) normal_to_d = vl.vdot(self.normal, D) # Check if parallel is_parallel = (abs(normal_to_d) < global_config.PARALLEL_EPSILON) non_parallel_indices = np.where(np.logical_not(is_parallel)) # Check Back Facing back_facing = normal_to_d > 0. t_hat = np.zeros([1, den.shape[1]]) if O.shape[1] > 1: num = num[non_parallel_indices] t_hat[non_parallel_indices] = num / den[non_parallel_indices] P = O + D * t_hat iot = self.inside_out_test(P) visible_mask = iot & (t_hat > 0.) & (np.logical_not(is_parallel)) & ( np.logical_not(back_facing * self.single_sided)) t = t_hat * visible_mask + global_config.MAX_DISTANCE * np.logical_not( visible_mask) t_out = t N_out = np.zeros_like(t) + self.normal M_out = O + t * D return t_out, M_out, N_out
def intersection(self, O, D): O_hat = vl.inverse_transform(self.T, O) D_hat = D t = vl.vdot(self.normal, -O_hat) / (vl.vdot(self.normal, D_hat)) pred = (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, M) N_out = np.ones_like(M_out) * self.normal return t_out, M_out, N_out
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 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): v0 = self.v0 v0v1 = self.v0v1 v0v2 = self.v0v2 p_vec = np.cross(D, v0v2, axis=0) det = vl.vdot(v0v1, p_vec) # Check Parallel is_parallel = abs(det) < global_config.PARALLEL_EPSILON non_parallel_indices = np.where(np.logical_not(is_parallel)) inv_det = np.ones_like(det) * global_config.MAX_DISTANCE inv_det[non_parallel_indices] = 1. / det[non_parallel_indices] # Check Backfacing backfacing = self.single_sided * (det > 0.) t_vec = (O - v0) u = vl.vdot(t_vec, p_vec) * inv_det u_mask = ((u < 0.) | (u > 1.)) q_vec = np.cross(t_vec, v0v1, axis=0) v = vl.vdot(D, q_vec) * inv_det w_mask = (v < 0.) | ((u + v) > 1.) t = vl.vdot(v0v2, q_vec) * inv_det visible_mask = (np.logical_not(u_mask | w_mask)) & (t > 0.) & ( np.logical_not(is_parallel)) & (np.logical_not(backfacing)) t_out = t * visible_mask + global_config.MAX_DISTANCE * np.logical_not( visible_mask) N_out = np.zeros_like(t) + self.normal M_out = O + t * D if not self.single_sided: normal_flip = -1. * (vl.vdot(D * visible_mask, self.normal) > 0.) N_out = N_out * normal_flip return t_out, M_out, N_out
def reflectance(self, s, N, V, 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) r_s = (n1 * cos_i - n2 * cos_t) / (n1 * cos_i + n2 * cos_t) r_p = (n2 * cos_i - n1 * cos_t) / (n2 * cos_i + n1 * cos_t) return np.where(sin_t2 > 1., 1., (r_s * r_s + r_p * r_p) / 2.0)
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 inside_out_test(self, P): P_min_V = P[:, None, :] - self.vertices[:, :, None] N = self.normal edges = [ self.vertices[:, i:i + 1] - self.vertices[:, i - 1:i] for i in range(1, self.vertices.shape[1]) ] edges.append(self.vertices[:, 0:1] - self.vertices[:, -1:]) edges = np.concatenate(edges, axis=1) W = np.cross(edges[:, :, None], P_min_V, axis=0) K = vl.vdot(N[:, :, None], W) inside = np.prod((K <= 0.), axis=1) return inside
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 reflect(self, V, N): return vl.vnorm(N * 2 * vl.vdot(V, N) - V)
def color_diffuse(self, s, N, to_L, intensity): lambert_color = np.maximum(vl.vdot(N, to_L), 0.) * s.material.surface_color return lambert_color * intensity * s.material.finish.diffuse
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