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
def init(): for i, j in A: if i == j: A[i, j] = 2.0 elif ti.abs(i-j) == 1: A[i, j] = -1.0 else: A[i, j] = 0.0 A[0, 0] = 1.0 A[0, 1] = 0.0 A[n-1, n-1] = 1.0 A[n-1, n-2] = 0.0 for i in b: b[i] = 0.0 x[i] = 0.0 b[0] = 100 b[n-1] = 0
def update_target_sdf(self): for I in ti.grouped(self.target_sdf): self.target_sdf[I] = self.inf grid_pos = ti.cast(I * self.dx, self.dtype) if self.target_density[I] > 1e-4: #TODO: make it configurable self.target_sdf[I] = 0. self.nearest_point[I] = grid_pos else: for offset in ti.grouped(ti.ndrange(*(((-3, 3),)*self.dim))): v = I + offset if v.min() >= 0 and v.max() < self.n_grid and ti.abs(offset).sum() != 0: if self.target_sdf_copy[v] < self.inf: nearest_point = self.nearest_point_copy[v] dist = self.norm(grid_pos - nearest_point) if dist < self.target_sdf[I]: self.nearest_point[I] = nearest_point self.target_sdf[I] = dist for I in ti.grouped(self.target_sdf): self.target_sdf_copy[I] = self.target_sdf[I] self.nearest_point_copy[I] = self.nearest_point[I]
def makePD2d(self, M: ti.template()): a = M[0, 0] b = (M[0, 1] + M[1, 0]) / 2 d = M[1, 1] b2 = b * b D = a * d - b2 T_div_2 = (a + d) / 2 sqrtTT4D = ti.sqrt(ti.abs(T_div_2 * T_div_2 - D)) L2 = T_div_2 - sqrtTT4D if L2 < 0.0: L1 = T_div_2 + sqrtTT4D if L1 <= 0.0: M = ti.zero(M) else: if b2 == 0: M = ti.Matrix([[L1, 0], [0, 0]]) else: L1md = L1 - d L1md_div_L1 = L1md / L1 M = ti.Matrix([[L1md_div_L1 * L1md, b * L1md_div_L1], [b * L1md_div_L1, b2 / L1]])
def _normal(self, f, grid_pos): p = ti.Vector([grid_pos[0], grid_pos[2]]) l = length(p) d = ti.Vector([l, ti.abs(grid_pos[1])]) - ti.Vector([self.h, self.r]) # if max(d) > 0, normal direction is just d # other wise it's 1 if d[1]>d[0] else -d0 # return min(max(d[0], d[1]), 0.0) + length(max(d, 0.0)) f = ti.cast(d[0] > d[1], self.dtype) n2 = max(d, 0.0) + ti.cast(max(d[0], d[1]) <= 0., self.dtype) * ti.Vector( [f, 1 - f]) # normal should be always outside .. n2_ = n2 / length(n2) p2 = p / l n3 = ti.Vector([ p2[0] * n2_[0], n2_[1] * (ti.cast(grid_pos[1] >= 0, self.dtype) * 2 - 1), p2[1] * n2_[0] ]) return normalize(n3)
def modify_springs(pos_x : ti.f32, pos_y : ti.f32) : eps = 0.003 for i in range(num_particles[None]): for j in range(i): # claculate the parameters of straight line general equation A = x[j].y - x[i].y B = x[i].x - x[j].x C = x[j].x * x[i].y - x[i].x * x[j].y norm = ti.sqrt(A * A + B * B) # calculate the distance of the point to the straight line dist = ti.abs((A * pos_x + B * pos_y + C) / norm) # r means AP.AB / ||AB|| r = ((pos_y - x[i].y) * A - (pos_x - x[i].x) * B) / (norm * norm) if dist < eps and 0 < r < 1: if rest_length[i, j] != 0: rest_length[i, j] = 0 rest_length[j, i] = 0 else: rest_length[i, j] = norm rest_length[j, i] = norm break
def q_to_primitive(self, q: ti.template()) -> ti.template(): rho = q[0] prim = ti.Vector([0.0, 0.0, 0.0, 0.0]) # (rho, u, v, e) if rho < 1e-10: # this should not happen, rho < 0 prim = ti.Vector([0.0, 0.0, 0.0, 0.0]) else: rho_inv = 1.0 / rho ux = q[1] * rho_inv uy = q[2] * rho_inv e = ti.abs(q[3] * rho_inv - 0.5 * (ux**2 + uy**2)) # TODO: abs or clamp? ### TODO: limit e to be > 0 # TODO: h -> e/p/h? prim = ti.Vector([rho, ux, uy, e]) ## others # p_on_rho = e * (self.gamma - 1.0) # p = p_on_rho * rho # a = (self.gamma * p_on_rho)**0.5 # uu = (ux**2 + uy**2)**0.5 # ma = uu / a # h = et + p/rho = e + 0.5 * uu + p / rho # t = Ma_far**2 * gamma * p / rho return prim
def sdfBox(p, length): p = ti.abs(p) - length d = ti.max(p, ti.Vector([0., 0., 0.])).norm() d += ti.min(ti.max(p[0], ti.max(p[1], p[2])), 0.) return d
def __abs__(self): _taichi_skip_traceback = 1 return ti.abs(self)
def _sdf(self, f, grid_pos): # p: vec3,b: vec3 q = ti.abs(grid_pos) - self.size[None] out = length(max(q, 0.0)) out += min(max(q[0], max(q[1], q[2])), 0.0) return out
def compute_density_loss_kernel(self): for I in ti.grouped(self.grid_mass): self.density_loss[None] += ti.abs(self.grid_mass[I] - self.target_density[I])
def func(): for i in range(N // 2 + 3, N): x[i] = ti.abs(y[i])
def foo(): x[None] = ti.abs(y[None])
def boxSDF(p, b): q = ti.abs(p) - b return length(ti.max(q, 0.0)) + ti.min(q.max(), 0.0)
def propagate_update(self, I, s): if self.valid[I] == -1: d = self.update_from_neighbor(I) if ti.abs(d) < ti.abs(self.phi_temp[I]): self.phi_temp[I] = d * ts.sign(self.phi[I]) return s
def plane(pos): return ts.length(ti.max(ti.abs(pos) - ts.vec(12.0, 0.5, 12.0), 0.0))
def rand3dT3d(t:ti.template)->ti.template: ret = ti.sin(t+0.546)*143758.5453 return ti.abs(ret-int(ret))
def is_fixed(self, ijk): return ti.abs(self.TSDF[ijk]) < ti.static(self.gamma)
def func(): for i in range(ti.static(N // 2 + 3), N): x[i] = ti.abs(y[i])
def __abs__(self): import taichi as ti _taichi_skip_traceback = 1 return ti.abs(self)
def dda_particle(eye_pos, d_, t): grid_res = particle_grid_res bbox_min = bbox[0] bbox_max = bbox[1] hit_pos = ti.Vector([0.0, 0.0, 0.0]) normal = ti.Vector([0.0, 0.0, 0.0]) c = ti.Vector([0.0, 0.0, 0.0]) d = d_ for i in ti.static(range(3)): if ti.abs(d[i]) < 1e-6: d[i] = 1e-6 inter, near, far = ray_aabb_intersection(bbox_min, bbox_max, eye_pos, d) near = ti.max(0, near) closest_intersection = inf if inter: pos = eye_pos + d * (near + eps) rinv = 1.0 / d rsign = ti.Vector([0, 0, 0]) for i in ti.static(range(3)): if d[i] > 0: rsign[i] = 1 else: rsign[i] = -1 o = grid_res * pos ipos = ti.Matrix.floor(o).cast(ti.i32) dis = (ipos - o + 0.5 + rsign * 0.5) * rinv running = 1 while running: inside = inside_particle_grid(ipos) if inside: num_particles = voxel_has_particle[ipos] if num_particles != 0: num_particles = ti.length(pid.parent(), ipos) for k in range(num_particles): p = pid[ipos[0], ipos[1], ipos[2], k] v = particle_v[p] x = particle_x[p] + t * v color = particle_color[p] dist, poss = intersect_sphere(eye_pos, d, x, sphere_radius) hit_pos = poss if dist < closest_intersection and dist > 0: hit_pos = eye_pos + dist * d closest_intersection = dist normal = ti.Matrix.normalized(hit_pos - x) c = [ color // 256**2 / 255.0, color / 256 % 256 / 255.0, color % 256 / 255.0 ] else: running = 0 normal = [0, 0, 0] if closest_intersection < inf: running = 0 else: # hits nothing. Continue ray marching mm = ti.Vector([0, 0, 0]) if dis[0] <= dis[1] and dis[0] <= dis[2]: mm[0] = 1 elif dis[1] <= dis[0] and dis[1] <= dis[2]: mm[1] = 1 else: mm[2] = 1 dis += mm * rsign * rinv ipos += mm * rsign return closest_intersection, normal, c
def computeNormalAndCurvature(): """ Compute the normal and the curvature at all points voxels. Based on the PC limplementation: https://pointclouds.org/documentation/group__features.html """ radius = 50 for i,j in pts: nb_pts = ti.cast(0, ti.f32) accu_0 = ti.cast(0, ti.f32) accu_1 = ti.cast(0, ti.f32) accu_2 = ti.cast(0, ti.f32) accu_3 = ti.cast(0, ti.f32) accu_4 = ti.cast(0, ti.f32) accu_5 = ti.cast(0, ti.f32) accu_6 = ti.cast(0, ti.f32) accu_7 = ti.cast(0, ti.f32) accu_8 = ti.cast(0, ti.f32) z = 0 for x in range(i-radius, i+radius): for y in range(j-radius, j+radius): if ti.is_active(block1, [x,y]): accu_0 += x * x accu_1 += x * y accu_2 += x * z accu_3 += y * y accu_4 += y * z accu_5 += z * z accu_6 += x accu_7 += y accu_8 += z nb_pts += 1 accu_0 /= nb_pts accu_1 /= nb_pts accu_2 /= nb_pts accu_3 /= nb_pts accu_4 /= nb_pts accu_5 /= nb_pts accu_6 /= nb_pts accu_7 /= nb_pts accu_8 /= nb_pts cov_mat_0 = accu_0 - accu_6 * accu_6 cov_mat_1 = accu_1 - accu_6 * accu_7 cov_mat_2 = accu_2 - accu_6 * accu_8 cov_mat_4 = accu_3 - accu_7 * accu_7 cov_mat_5 = accu_4 - accu_7 * accu_8 cov_mat_8 = accu_5 - accu_8 * accu_8 cov_mat_3 = cov_mat_1 cov_mat_6 = cov_mat_2 cov_mat_7 = cov_mat_5 # Compute eigen value and eigen vector # Make sure in [-1, 1] scale = ti.max(1.0, ti.abs(cov_mat_0)) scale = ti.max(scale, ti.abs(cov_mat_1)) scale = ti.max(scale, ti.abs(cov_mat_2)) scale = ti.max(scale, ti.abs(cov_mat_3)) scale = ti.max(scale, ti.abs(cov_mat_4)) scale = ti.max(scale, ti.abs(cov_mat_5)) scale = ti.max(scale, ti.abs(cov_mat_6)) scale = ti.max(scale, ti.abs(cov_mat_7)) scale = ti.max(scale, ti.abs(cov_mat_8)) if scale > 1.0: cov_mat_0 /= scale cov_mat_1 /= scale cov_mat_2 /= scale cov_mat_3 /= scale cov_mat_4 /= scale cov_mat_5 /= scale cov_mat_6 /= scale cov_mat_7 /= scale cov_mat_8 /= scale # Compute roots eigen_val_0 = ti.cast(0, ti.f32) eigen_val_1 = ti.cast(0, ti.f32) eigen_val_2 = ti.cast(0, ti.f32) c0 = cov_mat_0 * cov_mat_4 * cov_mat_8 \ + 2 * cov_mat_3 * cov_mat_6 * cov_mat_7 \ - cov_mat_0 * cov_mat_7 * cov_mat_7 \ - cov_mat_4 * cov_mat_6 * cov_mat_6 \ - cov_mat_8 * cov_mat_3 * cov_mat_3 c1 = cov_mat_0 * cov_mat_4 \ - cov_mat_3 * cov_mat_3 \ + cov_mat_0 * cov_mat_8 \ - cov_mat_6 * cov_mat_6 \ + cov_mat_4 * cov_mat_8 \ - cov_mat_7 * cov_mat_7 c2 = cov_mat_0 + cov_mat_4 + cov_mat_8 if ti.abs(c0) < 0.00001: eigen_val_0 = 0 d = c2 * c2 - 4.0 * c1 if d < 0.0: # no real roots ! THIS SHOULD NOT HAPPEN! d = 0.0 sd = ti.sqrt(d) eigen_val_2 = 0.5 * (c2 + sd) eigen_val_1 = 0.5 * (c2 - sd) else: s_inv3 = ti.cast(1.0 / 3.0, ti.f32) s_sqrt3 = ti.sqrt(3.0) c2_over_3 = c2 * s_inv3 a_over_3 = (c1 - c2 * c2_over_3) * s_inv3 if a_over_3 > 0: a_over_3 = 0 half_b = 0.5 * (c0 + c2_over_3 * (2 * c2_over_3 * c2_over_3 - c1)) q = half_b * half_b + a_over_3 * a_over_3 * a_over_3 if q > 0: q = 0 rho = ti.sqrt(-a_over_3) theta = ti.atan2(ti.sqrt(-q), half_b) * s_inv3 cos_theta = ti.cos(theta) sin_theta = ti.sin(theta) eigen_val_0 = c2_over_3 + 2 * rho * cos_theta eigen_val_1 = c2_over_3 - rho * (cos_theta + s_sqrt3 * sin_theta) eigen_val_2 = c2_over_3 - rho * (cos_theta - s_sqrt3 * sin_theta) temp_swap = ti.cast(0, ti.f32) # Sort in increasing order. if eigen_val_0 >= eigen_val_1: temp_swap = eigen_val_1 eigen_val_1 = eigen_val_0 eigen_val_0 = temp_swap if eigen_val_1 >= eigen_val_2: temp_swap = eigen_val_2 eigen_val_2 = eigen_val_1 eigen_val_1 = temp_swap if eigen_val_0 >= eigen_val_1: temp_swap = eigen_val_1 eigen_val_1 = eigen_val_0 eigen_val_0 = temp_swap if eigen_val_0 <= 0: eigen_val_0 = 0 d = c2 * c2 - 4.0 * c1 if d < 0.0: # no real roots ! THIS SHOULD NOT HAPPEN! d = 0.0 sd = ti.sqrt(d) eigen_val_2 = 0.5 * (c2 + sd) eigen_val_1 = 0.5 * (c2 - sd) # end of compute roots eigen_value = eigen_val_1 * scale # eigen value for 2D SDF # eigen value for 3D SDF #eigen_value = eigen_val_0 * scale #print("eigen_val_0 ", eigen_val_0) #print("eigen_val_1 ", eigen_val_1) #print("eigen_val_2 ", eigen_val_2) # TODO #scaledMat.diagonal ().array () -= eigenvalues (0) #eigenvector = detail::getLargest3x3Eigenvector<Vector> (scaledMat).vector; # Compute normal vector (TODO) #visual_norm[i,j][0] = eigen_val_0 #eigen_vector[0] #visual_norm[i,j][1] = eigen_val_1 #eigen_vector[1] #visual_norm[i,j][2] = eigen_val_2 #eigen_vector[2] # Compute the curvature surface change eig_sum = cov_mat_0 + cov_mat_1 + cov_mat_2 visual_curv[i,j][0] = 0 if eig_sum != 0: visual_curv[i,j][0] = eigen_val_1 # true curvature is: ti.abs(eigen_value / eig_sum)
def func(): for i in range(begin, end): x[i] = ti.abs(y[i])
def particle_to_grid(): # clear grid for k in ti.grouped(velocities): velocities[k] = ti.Vector([0.0, 0.0]) weights[k] = 0.0 divergences[k] = 0.0 # pressures[k] = 0.0 new_pressures[k] = 0.0 # pressures[k] = 0.0 if types[k] != SOLID: types[k] = AIR velocities[k] += ti.Vector([0.0, -9.8]) * dt for k in particle_velocity: p = particle_position[k] p_g = p * m_g # change cell type to 'fluid' types[p_g.cast(int)] = FLUID # find left bottom corner # base = (p_g - stagger).cast(int) base = (p_g - 1).cast(int) fx = p_g - base.cast(float) # quadratic B-spline # w = [0.5 * (1.5-fx)**2, 0.75 - (fx-1)**2, 0.5 * (fx-0.5)**2] w = [0.5 * (1.5-(fx-0.5))**2, 0.75 - (ti.abs(fx-1.5))**2, 0.5 * (1.5-(2.5-fx))**2] # print(w) for i in ti.static(range(3)): for j in ti.static(range(3)): offset = ti.Vector([i, j]) weight = w[i][0] * w[j][1] # print(weight) grid_idx = base + offset velocities[grid_idx] += weight * particle_velocity[k] weights[grid_idx] += weight # if types[grid_idx] != SOLID: # types[grid_idx] = FLUID # mx = 0.0 # mi = 1e20 # c = 0 for k in ti.grouped(weights): weight = weights[k] # mx = max(mx, weight) # mi = min(mi, weight) # if weight > 0 and weight < eps: # print(weight) if types[k] == SOLID: weights[k] = 0.0 velocities[k] = ti.Vector([0.0, 0.0]) if weight > 0: # c += 1 tv = velocities[k] velocities[k] = velocities[k] / weight
def __abs__(self): import taichi as ti return ti.abs(self)
def grid_to_particle(): for k in particle_velocity: p = particle_position[k] p_g = p * m_g # find left bottom corner # base = (p_g - stagger).cast(int) base = (p_g - 1).cast(int) fx = p_g - base.cast(float) # quadratic B-spline # w = [0.5 * (1.5-fx)**2, 0.75 - (fx-1)**2, 0.5 * (fx-0.5)**2] w = [0.5 * (1.5-(fx-0.5))**2, 0.75 - (ti.abs(fx-1.5))**2, 0.5 * (1.5-(2.5-fx))**2] new_v = ti.Vector.zero(ti.f32, 2) for i in ti.static(range(3)): for j in ti.static(range(3)): offset = ti.Vector([i, j]) weight = w[i][0] * w[j][1] new_v += weight * velocities[base + offset] new_p = p + new_v * dt # damp = 0.99 # normal = ti.Vector([0.0, 0.0]) # if new_p.x < dx: # new_p.x = dx # normal.x += -1.0 # if new_p.x > 1 - dx: # new_p.x = 1 - dx # normal.x += 1.0 # if new_p.y < 0.05: # new_p.y = 0.05 # normal.y += -1.0 # if new_p.y > 0.95: # new_p.y = 0.95 # normal.y += 1.0 # nl = normal.norm() # vl = new_v.norm() # if nl > 0.1 and vl > 0.1: # normal /= nl # new_v -= normal * vl if new_p.x < dx*2: new_p.x = dx*2 new_v.x = 0 if new_p.x >= 1 - dx*2: new_p.x = 1 - dx*2 - eps new_v.x = 0 if new_p.y < dx*2: new_p.y = dx*2 new_v.y = 0 if new_p.y >= 1 - dx*2: new_p.y = 1 - dx*2 - eps new_v.y = 0 # ??????????????? particle_position[k] = new_p particle_velocity[k] = new_v