def render_refract(t: ti.i32): for i in range(n_grid): # Parallelized over GPU threads for j in range(n_grid): grad = height_gradient[i, j] scale = 2.0 sample_x = i - grad[0] * scale sample_y = j - grad[1] * scale sample_x = ti.min(n_grid - 1, ti.max(0, sample_x)) sample_y = ti.min(n_grid - 1, ti.max(0, sample_y)) sample_xi = ti.cast(ti.floor(sample_x), ti.i32) sample_yi = ti.cast(ti.floor(sample_y), ti.i32) frac_x = sample_x - sample_xi frac_y = sample_y - sample_yi for k in ti.static(range(3)): refracted_image[i, j, k] = (1.0 - frac_x) * ( (1 - frac_y) * bottom_image[sample_xi, sample_yi, k] + frac_y * bottom_image[ sample_xi, sample_yi + 1, k]) + frac_x * ( (1 - frac_y) * bottom_image[ sample_xi + 1, sample_yi, k] + frac_y * bottom_image[ sample_xi + 1, sample_yi + 1, k] )
def process_new_pcl(self): count = 0 for i, j, k in self.new_pcl_count: c = self.new_pcl_count[i, j, k] pos_s2p = self.new_pcl_sum_pos[i, j, k]/c len_pos_s2p = pos_s2p.norm() d_s2p = pos_s2p /len_pos_s2p pos_p = pos_s2p + self.input_T[None] z = pos_s2p[2] j_f = 0.0 ray_cast_voxels = ti.min(len_pos_s2p/self.voxel_size+ti.static(self.internal_voxels), self.max_ray_length/self.voxel_size) for _j in range(ray_cast_voxels): j_f += 1.0 x_ = d_s2p*j_f*self.voxel_size + self.input_T[None] xi = self.xyz_to_ijk(x_) xi = self.constrain_coor(xi) #vector from current voxel to point, e.g. p-x v2p = pos_p - x_ d_x_p = v2p.norm() d_x_p_s = d_x_p*sign(v2p.dot(pos_p)) w_x_p = 1.0#self.w_x_p(d_x_p, z) self.TSDF[xi] = (self.TSDF[xi]*self.W_TSDF[xi]+w_x_p*d_x_p_s)/(self.W_TSDF[xi]+w_x_p) self.TSDF_observed[xi] = 1 self.W_TSDF[xi] = ti.min(self.W_TSDF[xi]+w_x_p, Wmax) self.updated_TSDF[xi] = 1 count += 1 if ti.static(self.TEXTURE_ENABLED): self.color[xi] = self.new_pcl_sum_color[i, j, k]/ c/255.0
def sdfscene(p, t=0): center = ti.Vector([-3., 1, 6.]) radius = .5 planesdf = p.y spheresdf = sdfsphere(p, center, radius) torussdf = sdfTorus(p, ti.Vector([0, 0.5, 7]), ti.Vector([1.58, .2])) capsulesdf = sdfCapsule(p, ti.Vector([0.4, 0.3, 6]), ti.Vector([0.7, 1.5, 6.]), .2) bp = p - ti.Vector([-3.4, 0.5, 6]) # translation tmpbp = ti.Vector([bp[0], bp[2]]) tmpbp = Rot(t) @ tmpbp bp[0] = tmpbp[0] bp[2] = tmpbp[1] boxsdf = sdfBox(bp, ti.Vector([0.5, 0.5, 0.5])) d = smoothmin(boxsdf, spheresdf, 0.4) d = ti.min(planesdf, d) d = ti.min(torussdf, d) d = ti.min(capsulesdf, d) #blend shapes together to form the scene bp = p - ti.Vector([3.5, 0.5, 6]) dbox = sdfBox(bp, ti.Vector([0.5, 0.5, 0.5])) dball = sdfsphere(p, ti.Vector([3.5, 0.5, 6]), radius) blend = mix(dbox, dball, ti.sin(t) * .5 + .5) d = ti.min(blend, d) return d
def render_photon_map(t: ti.i32, offset_x: ti.f32, offset_y: ti.f32): for i in range(n_grid): # Parallelized over GPU threads for j in range(n_grid): grad = height_gradient[i, j] * (1 - offset_x) * (1 - offset_y) + \ height_gradient[i + 1, j] * offset_x * (1 - offset_y) + \ height_gradient[i, j + 1] * (1 - offset_x) * offset_y + \ height_gradient[i + 1, j + 1] * offset_x * offset_y scale = 5.0 sample_x = i - grad[0] * scale + offset_x sample_y = j - grad[1] * scale + offset_y sample_x = ti.min(n_grid - 1, ti.max(0, sample_x)) sample_y = ti.min(n_grid - 1, ti.max(0, sample_y)) sample_xi = ti.cast(ti.floor(sample_x), ti.i32) sample_yi = ti.cast(ti.floor(sample_y), ti.i32) frac_x = sample_x - sample_xi frac_y = sample_y - sample_yi x = sample_xi y = sample_yi ti.atomic_add(rendered[x, y], (1 - frac_x) * (1 - frac_y)) ti.atomic_add(rendered[x, y + 1], (1 - frac_x) * frac_y) ti.atomic_add(rendered[x + 1, y], frac_x * (1 - frac_y)) ti.atomic_add(rendered[x + 1, y + 1], frac_x * frac_y)
def intersect_aabb(box_min, box_max, o, d): intersect = 1 near_t = -inf far_t = inf near_face = 0 near_is_max = 0 for i in ti.static(range(3)): if d[i] == 0: if o[i] < box_min[i] or o[i] > box_max[i]: intersect = 0 else: i1 = (box_min[i] - o[i]) / d[i] i2 = (box_max[i] - o[i]) / d[i] new_far_t = ti.max(i1, i2) new_near_t = ti.min(i1, i2) new_near_is_max = i2 < i1 far_t = ti.min(new_far_t, far_t) if new_near_t > near_t: near_t = new_near_t near_face = int(i) near_is_max = new_near_is_max near_norm = ti.Vector([0.0, 0.0, 0.0]) if near_t > far_t: intersect = 0 if intersect: for i in ti.static(range(2)): if near_face == i: near_norm[i] = -1 + near_is_max * 2 return intersect, near_t, far_t, near_norm
def test_minmax(): grad_test(lambda x: ti.min(x, 0), lambda x: np.minimum(x, 0)) grad_test(lambda x: ti.min(x, 1), lambda x: np.minimum(x, 1)) grad_test(lambda x: ti.min(0, x), lambda x: np.minimum(0, x)) grad_test(lambda x: ti.min(1, x), lambda x: np.minimum(1, x)) grad_test(lambda x: ti.max(x, 0), lambda x: np.maximum(x, 0)) grad_test(lambda x: ti.max(x, 1), lambda x: np.maximum(x, 1)) grad_test(lambda x: ti.max(0, x), lambda x: np.maximum(0, x)) grad_test(lambda x: ti.max(1, x), lambda x: np.maximum(1, x))
def get_neigbour_min(self, i, j, mod, src): out_min = src[i, j] if i + mod < self.wid - 1: out_min = ti.min(out_min, src[i + mod, j]) if j + mod < self.hgt - 1: out_min = ti.min(out_min, src[i, j + mod]) if (j + mod < self.hgt - 1) & (i + mod < self.wid - mod): out_min = ti.min(out_min, src[i + mod, j + mod]) return out_min
def tile_culling(self): for i, j in self.block_num_triangles: idx = 0 tile_min = ti.Vector([i * tile_size, j * tile_size]) tile_max = ti.Vector([(i + 1) * tile_size, (j + 1) * tile_size]) for t in range(self.n): A, B, C = self.A[t], self.B[t], self.C[t] tri_min = ti.min(A, ti.min(B, C)) tri_max = ti.max(A, ti.max(B, C)) if self.bbox_intersect(tile_min, tile_max, tri_min, tri_max): self.block_indicies[i, j, idx] = t idx = idx + 1 self.block_num_triangles[i, j] = idx
def time_integrate(t: ti.i32): for i in range(n_objects): s = math.exp(-dt * damping) new_v = s * v[t - 1, i] + dt * force[t, i] / mass new_x = x[t - 1, i] + dt * new_v if new_x[0] > 0.4 and new_v[0] > 0: # friction projection if new_v[1] > 0: new_v[1] -= ti.min(new_v[1], friction * new_v[0]) if new_v[1] < 0: new_v[1] += ti.min(-new_v[1], friction * new_v[0]) new_v[0] = 0 v[t, i] = new_v x[t, i] = new_x
def collide(t: ti.i32): for i in range(n_objects): hs = halfsize[i] for k in ti.static(range(4)): # the corner for collision detection offset_scale = ti.Vector([k % 2 * 2 - 1, k // 2 % 2 * 2 - 1]) corner_x, corner_v, rela_pos = to_world(t, i, offset_scale * hs) corner_v = corner_v + dt * gravity * ti.Vector([0.0, 1.0]) # Apply impulse so that there's no sinking normal = ti.Vector([0.0, 1.0]) tao = ti.Vector([1.0, 0.0]) rn = cross(rela_pos, normal) rt = cross(rela_pos, tao) impulse_contribution = inverse_mass[i] + ti.sqr(rn) * \ inverse_inertia[i] timpulse_contribution = inverse_mass[i] + ti.sqr(rt) * \ inverse_inertia[i] rela_v_ground = normal.dot(corner_v) impulse = 0.0 timpulse = 0.0 new_corner_x = corner_x + dt * corner_v toi = 0.0 if rela_v_ground < 0 and new_corner_x[1] < ground_height: impulse = -(1 + elasticity) * rela_v_ground / impulse_contribution if impulse > 0: # friction timpulse = -corner_v.dot(tao) / timpulse_contribution timpulse = ti.min(friction * impulse, ti.max(-friction * impulse, timpulse)) if corner_x[1] > ground_height: toi = -(corner_x[1] - ground_height) / ti.min( corner_v[1], 1e-3) apply_impulse(t, i, impulse * normal + timpulse * tao, new_corner_x, toi) penalty = 0.0 if new_corner_x[1] < ground_height: # apply penalty penalty = -dt * penalty * ( new_corner_x[1] - ground_height) / impulse_contribution apply_impulse(t, i, penalty * normal, new_corner_x, 0)
def initialize_particle_x(x: np.ndarray, v: np.ndarray, color: np.ndarray): for i in range(max_num_particles): if i < num_particles: for c in ti.static(range(3)): particle_x[i][c] = x[i * 3 + c] for c in ti.static(range(3)): particle_v[i][c] = v[i * 3 + c] # v_c = ti.min(1, particle_v[i].norm()) * 1.5 # ti.print(v_c) if ti.static(scene == 'fluid'): v_c = ti.min(particle_v[i].norm() * 0.1, 1) particle_color[i] = rgb_to_i32(v_c * 0.3 + 0.3, v_c * 0.4 + 0.4, 0.5 + v_c * 0.5) elif ti.static(scene == 'sand'): particle_color[i] = ti.cast(color[i], ti.i32) else: particle_color[i] = rgb_to_i32(0.85, 0.90, 1.0) # reconstruct grid using particle position and MPM p2g. for k in ti.static(range(27)): base_coord = (inv_dx * particle_x[i] - 0.5).cast( ti.i32) + ti.Vector([k // 9, k // 3 % 3, k % 3]) grid_density[base_coord / grid_visualization_block_size] = 1
def _sdf(self, f, grid_pos): delta = ti.Vector([self.gap[f] / 2, 0., 0.]) p = grid_pos - ti.Vector([0., -self.h / 2, 0.]) a = super(Chopsticks, self)._sdf(f, p - delta) # grid_pos - (mid + delta) b = super(Chopsticks, self)._sdf(f, p + delta) # grid_pos - (mid - delta) return ti.min(a, b)
def set_action(t: ti.i32): cur = 0 for i in ti.static(range(len(self.primitives))): p = self.primitives[i] if ti.static(p.action_dim>0): for j in ti.static(range(p.action_dim)): p.action_buffer[t][j] = ti.max(ti.min(h[t, cur+j], 1.), -1.) cur += p.action_dim
def get_final_image_nondiff(self): ''' Retrieves the final image from the tape if the `raycast_nondiff` method was used. ''' for i, j in self.valid_sample_step_count: valid_sample_step_count = self.valid_sample_step_count[i, j] - 1 self.output_rgba[i, j] = ti.min(1.0, self.render_tape[i, j, 0]) if valid_sample_step_count > self.max_valid_sample_step_count[None]: self.max_valid_sample_step_count[ None] = valid_sample_step_count
def kernel(angle: ti.f32, view_id: ti.i32): for pixel in range(res * res): for k in range(marching_steps): x = pixel // res y = pixel - x * res camera_origin = ti.Vector([ camera_origin_radius * ti.sin(angle), 0, camera_origin_radius * ti.cos(angle) ]) dir = ti.Vector([ fov * (ti.cast(x, ti.f32) / (res_f32 / 2.0) - res_f32 / res_f32), fov * (ti.cast(y, ti.f32) / (res_f32 / 2.0) - 1.0), -1.0 ]) length = ti.sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]) dir /= length rotated_x = dir[0] * ti.cos(angle) + dir[2] * ti.sin(angle) rotated_z = -dir[0] * ti.sin(angle) + dir[2] * ti.cos(angle) dir[0] = rotated_x dir[2] = rotated_z point = camera_origin + (k + 1) * dx * dir # Convert to coordinates of the density grid box box_x = point[0] + 0.5 box_y = point[1] + 0.5 box_z = point[2] + 0.5 # Density grid location index_x = ti.cast(ti.floor(box_x * density_res), ti.i32) index_y = ti.cast(ti.floor(box_y * density_res), ti.i32) index_z = ti.cast(ti.floor(box_z * density_res), ti.i32) index_x = ti.max(0, ti.min(index_x, density_res - 1)) index_y = ti.max(0, ti.min(index_y, density_res - 1)) index_z = ti.max(0, ti.min(index_z, density_res - 1)) flag = 0 if in_box(point[0], point[1], point[2]): flag = 1 contribution = density[index_z, index_y, index_x] * flag ti.atomic_add(field[view_id, y, x], contribution)
def clamp(x, low, high): """ Получение наиболее близкого значения в заданном диапазоне :param x: исходное значение :param low: нижняя граница :param high: верзняя граница :return: новое значение в границах low и high """ return ti.max(ti.min(x, high), low)
def softray(ro, rd, hn): res = 1.0 t = 0.0005 h = 1.0 for _ in range(0, 40): h = scene(ro + rd * t) res = ti.min(res, hn * h / t) t += ts.clamp(h, 0.02, 2.0) return ts.clamp(res, 0.0, 1.0)
def foo(): # Parallel min for i in range(1000): ti.atomic_min(f[0], -3.13 * i) # Serial min for _ in range(1): for i in range(1000): f[1] = ti.min(-3.13 * i, f[1])
def SdfNormalCapsule(X, radius, half_length): unclamped_alpha = (X[0] / half_length + 1.0) * 0.5 alpha = ti.min(ti.max(unclamped_alpha, 0.0), 1.0) normal = ti.Vector([X[0], X[1]]) normal[0] += (1.0 - 2.0 * alpha) * half_length ltmp = ti.max(1e-12, normal.norm()) normal[0] /= ltmp normal[1] /= ltmp if unclamped_alpha >= 0.0 and unclamped_alpha <= 1.0: normal[0] = 0.0 return normal
def apply_impulse(t, i, impulse, location, toi_input): # ti.print(toi) delta_v = impulse * inverse_mass[i] delta_omega = cross(location - x[t, i], impulse) * inverse_inertia[i] toi = ti.min(ti.max(0.0, toi_input), dt) ti.atomic_add(x_inc[t + 1, i], toi * (-delta_v)) ti.atomic_add(rotation_inc[t + 1, i], toi * (-delta_omega)) ti.atomic_add(v_inc[t + 1, i], delta_v) ti.atomic_add(omega_inc[t + 1, i], delta_omega)
def add_block(x: ti.f32): if n_s_particles < 40000 - 1000: for i in range(n_s_particles, n_s_particles + 1000): x_s[i] = [ ti.min(0.87, x) + ti.random() * 0.1, ti.random() * 0.1 + 0.87 ] v_s[i] = ti.Matrix([0, -0.25]) F_s[i] = ti.Matrix([[1, 0], [0, 1]]) c_C0[i] = -0.01 alpha_s[i] = 0.267765 n_s_particles += 1000
def linearSolve(self, x, b, relative_tolerance): self.linear_solver_data.deactivate_all() self.linearSolverReinitialize() # NOTE: requires that the input x has been projected # self.multiply(x, self.temp) self.scaledCopy(self.r, b, -1, self.temp) self.kernelProject(self.r) self.precondition( self.r, self.q) # NOTE: requires that preconditioning matrix is projected self.copy(self.p, self.q) zTrk = self.dotProduct(self.r, self.q) # print('\033[1;36mzTrk = ', zTrk, '\033[0m') residual_preconditioned_norm = ti.sqrt(zTrk) local_tolerance = self.real( ti.min(relative_tolerance * residual_preconditioned_norm, self.linear_solve_tolerance)) for cnt in range(self.linear_solve_max_iterations): if ti.static(self.debug_mode): print('\033[1;33mlinear_iter = ', cnt, ', residual_preconditioned_norm = ', residual_preconditioned_norm, '\033[0m') if residual_preconditioned_norm <= local_tolerance: return cnt self.multiply(self.p, self.temp) self.kernelProject(self.temp) alpha = zTrk / self.dotProduct(self.temp, self.p) print('\033[1;36malpha = ', alpha, '\033[0m') self.scaledCopy(x, x, alpha, self.p) # i.e. x += p * alpha self.scaledCopy(self.r, self.r, -alpha, self.temp) # i.e. r -= temp * alpha self.precondition( self.r, self.q ) # NOTE: requires that preconditioning matrix is projected zTrk_last = zTrk zTrk = self.dotProduct(self.q, self.r) print('\033[1;36mzTrk = ', zTrk, '\033[0m') beta = zTrk / zTrk_last print('\033[1;36mbeta = ', beta, '\033[0m') self.scaledCopy(self.p, self.q, beta, self.p) # i.e. p = q + beta * p residual_preconditioned_norm = ti.sqrt(zTrk) return self.linear_solve_max_iterations
def ray_aabb_intersection(box_min, box_max, o, d): intersect = 1 near_int = -inf far_int = inf for i in ti.static(range(3)): if d[i] == 0: if o[i] < box_min[i] or o[i] > box_max[i]: intersect = 0 else: i1 = (box_min[i] - o[i]) / d[i] i2 = (box_max[i] - o[i]) / d[i] new_far_int = ti.max(i1, i2) new_near_int = ti.min(i1, i2) far_int = ti.min(new_far_int, far_int) near_int = ti.max(new_near_int, near_int) if near_int > far_int: intersect = 0 return intersect, near_int, far_int
def ray_aabb_intersection(box_min, box_max, o, d): intersect = 1 near_int = -inf far_int = inf for i in ti.static(range(3)): if d[i] == 0: if o[i] < box_min[i] or o[i] > box_max[ i]: # if any component of ray origin is outside bbox intersect = 0 #intersection is false else: i1 = (box_min[i] - o[i]) / d[i] i2 = (box_max[i] - o[i]) / d[i] new_far_int = ti.max(i1, i2) new_near_int = ti.min(i1, i2) far_int = ti.min(new_far_int, far_int) near_int = ti.max(new_near_int, near_int) if near_int > far_int: intersect = 0 return intersect, near_int, far_int
def intersect_hull(gx: ti.f32, gy: ti.f32, gz: ti.f32, k_len: ti.i32, hull_len: ti.i32): g = ti.Vector([gx, gy, gz]) for i in range(k_len): c = hull_p[i] d = c - g h = c for j in range(hull_len): ok, p = intersect_triangle(g, d, hull_p[hull_f[j][0]], hull_p[hull_f[j][1]], hull_p[hull_f[j][2]]) if ok: h = p break k[i] = ti.min( ti.max(ti.sqrt((c - g).dot(c - g) / (h - g).dot(h - g)), 0.0), 1.0)
def util_ti_scale_value_to_color(self, c) -> ti.i32: max_value = self.display_value_max min_value = self.display_value_min v = (c - min_value) / (max_value - min_value) value = 0 if ti.static(self.display_color_map == 0): # map [0,1] ~ gray color 0~255 color_gray = ti.min(255, ti.max(0, v * 256.0)) value = ti.cast(color_gray, ti.i32) * 0x010101 else: r = self.util_color_map_value(0x01, 0xff, v) g = self.util_color_map_value(0x20, 0xbb, v) b = self.util_color_map_value(0xff, 0x00, v) value = r * 0x010000 + g * 0x0100 + b return value
def _cook(self, color): if isinstance(color, ti.Expr): color = ti.Vector([color, color, color]) elif isinstance(color, ti.Matrix): assert color.m == 1, color.m if color.n == 1: color = ti.Vector([color(0), color(0), color(0)]) elif color.n == 2: color = ti.Vector([color(0), color(1), 0]) elif color.n in [3, 4]: color = ti.Vector([color(0), color(1), color(2)]) else: assert False, color.n if self.img.meta.dtype not in [ti.u8, ti.i8]: color = ti.max(0, ti.min(255, ti.cast(color * 255 + 0.5, int))) return color
def func(): x[0] = y[None] + z[None] x[1] = y[None] - z[None] x[2] = y[None] * z[None] x[3] = y[None] / z[None] x[4] = y[None] // z[None] x[5] = y[None] % z[None] x[6] = y[None]**z[None] x[7] = y[None] == z[None] x[8] = y[None] != z[None] x[9] = y[None] > z[None] x[10] = y[None] >= z[None] x[11] = y[None] < z[None] x[12] = y[None] <= z[None] x[13] = ti.atan2(y[None], z[None]) x[14] = ti.min(y[None], z[None]) x[15] = ti.max(y[None], z[None])
def raycast(self, sampling_rate: float): ''' Produce a rendering. Run compute_entry_exit first! ''' for i, j in self.valid_sample_step_count: # For all pixels for sample_idx in range(self.sample_step_nums[i, j]): look_from = self.cam_pos[None] if self.render_tape[i, j, sample_idx - 1].w < 0.99 and sample_idx < ti.static( self.max_samples): tmax = self.exit[i, j] n_samples = self.sample_step_nums[i, j] ray_len = (tmax - self.entry[i, j]) tmin = self.entry[ i, j] + 0.5 * ray_len / n_samples # Offset tmin as t_start vd = self.rays[i, j] pos = look_from + tl.mix( tmin, tmax, float(sample_idx) / float(n_samples - 1)) * vd # Current Pos light_pos = look_from + tl.vec3(0.0, 1.0, 0.0) intensity = self.sample_volume_trilinear(pos) sample_color = self.apply_transfer_function(intensity) opacity = 1.0 - ti.pow(1.0 - sample_color.w, 1.0 / sampling_rate) # if sample_color.w > 1e-3: normal = self.get_volume_normal(pos) light_dir = ( pos - light_pos).normalized() # Direction to light source n_dot_l = max(normal.dot(light_dir), 0.0) diffuse = self.diffuse * n_dot_l r = tl.reflect(light_dir, normal) # Direction of reflected light r_dot_v = max(r.dot(-vd), 0.0) specular = self.specular * pow(r_dot_v, self.shininess) shaded_color = tl.vec4( ti.min(1.0, diffuse + specular + self.ambient) * sample_color.xyz * opacity * self.light_color, opacity) self.render_tape[i, j, sample_idx] = ( 1.0 - self.render_tape[i, j, sample_idx - 1].w ) * shaded_color + self.render_tape[i, j, sample_idx - 1] self.valid_sample_step_count[i, j] += 1 else: self.render_tape[i, j, sample_idx] = self.render_tape[ i, j, sample_idx - 1]
def sdf(o_): if ti.static(supporter == 0): o = o_ - ti.Vector([0.5, 0.002, 0.5]) p = o h = 0.02 ra = 0.29 rb = 0.005 d = (ti.Vector([p[0], p[2]]).norm() - 2.0 * ra + rb, ti.abs(p[1]) - h) dist = ti.min(ti.max(d[0], d[1]), 0.0) + ti.Vector( [ti.max(d[0], 0.0), ti.max(d[1], 0)]).norm() - rb return dist elif ti.static(supporter == 1): o = o_ - ti.Vector([0.5, 0.002, 0.5]) dist = (o.abs() - ti.Vector([0.5, 0.02, 0.5])).max() else: dist = o_[1] - 0.04 return dist