def apply_impulse(vf: ti.types.ndarray(field_dim=2), dyef: ti.types.ndarray(field_dim=2), imp_data: ti.types.ndarray(field_dim=1)): g_dir = -ti.Vector([0, 9.8]) * 300 for i, j in vf: omx, omy = imp_data[2], imp_data[3] mdir = ti.Vector([imp_data[0], imp_data[1]]) dx, dy = (i + 0.5 - omx), (j + 0.5 - omy) d2 = dx * dx + dy * dy # dv = F * dt factor = ti.exp(-d2 / force_radius) dc = dyef[i, j] a = dc.norm() momentum = (mdir * f_strength * factor + g_dir * a / (1 + a)) * dt v = vf[i, j] vf[i, j] = v + momentum # add dye if mdir.norm() > 0.5: dc += ti.exp(-d2 * (4 / (res / 15)**2)) * ti.Vector( [imp_data[4], imp_data[5], imp_data[6]]) dyef[i, j] = dc
def mainImage(iMouse: ti.Vector, iTime: ti.f32, i: ti.i32, j: ti.i32) -> ti.Vector: fragCoord = ti.Vector([i, j]) p = -1.0 + 2.0 * fragCoord / iResolution m = -1.0 + 2.0 * iMouse # iMouse 已经归一化 a1 = ti.atan2(p[1] - m[1], p[0] - m[0]) a2 = ti.atan2(p[1] + m[1], p[0] + m[0]) r1 = ti.sqrt((p - m).dot(p - m)) r2 = ti.sqrt((p + m).dot(p + m)) uv = ti.Vector( [0.2 * iTime + (r1 - r2) * 0.25, ti.asin(ti.sin(a1 - a2)) / 3.1416]) w = ti.exp(-15.0 * r1 * r1) + ti.exp(-15.0 * r2 * r2) w += 0.25 * smoothstep(0.93, 1.0, ti.sin(128.0 * uv[0])) w += 0.25 * smoothstep(0.93, 1.0, ti.sin(128.0 * uv[1])) # 可以使用纹理 # vec3 col = texture( iChannel0, 0.125*uv ).zyx; col = ti.Vector([0.0, 0.0, 0.0]) fragColor = col + w return fragColor
def apply_mouse_input_and_render(self, vf: ti.template(), dyef: ti.template(), imp_data: ti.ext_arr(), dt: ti.template()): for i, j in vf: mdir = ti.Vector([imp_data[0], imp_data[1]]) omx, omy = imp_data[2], imp_data[3] # move to cell center dx, dy = (i + 0.5 - omx), (j + 0.5 - omy) d2 = dx * dx + dy * dy # ref: https://developer.download.nvidia.cn/books/HTML/gpugems/gpugems_ch38.html # apply the force factor = ti.exp(-d2 * self.cfg.inv_force_radius) momentum = mdir * self.cfg.f_strength * dt * factor vf[i, j] += momentum # add dye dc = dyef[i, j] # TODO what the hell is this? if mdir.norm() > 0.5: dc += ti.exp(-d2 * self.cfg.inv_dye_denom) * ti.Vector( [imp_data[4], imp_data[5], imp_data[6]]) dc *= self.cfg.dye_decay dyef[i, j] = dc
def initialize_vortices(): for i, j in ux: s = 0.16 x = xCoord(i) * 2.0 y = yCoord(j) * 2.0 x0 = x - s x1 = x + s ux_ = 0.0 uy_ = 0.0 # add vortex rr1 = sq(x0) + sq(y) ux_ += -y * ti.exp(-rr1 / (2.0 * sq(0.12))) * 25.0 uy_ += x0 * ti.exp(-rr1 / (2.0 * sq(0.12))) * 25.0 # add vortex rr2 = sq(x1) + sq(y) ux_ += -y * ti.exp(-rr2 / (2.0 * sq(0.12))) * 25.0 uy_ += x1 * ti.exp(-rr2 / (2.0 * sq(0.12))) * 25.0 ux[i, j] = ux_ uy[i, j] = uy_ for i, j in omega: i_p = mod(i + 1, Nx) i_n = mod(i - 1 + Nx, Nx) j_p = mod(j + 1, Ny) j_n = mod(j - 1 + Ny, Ny) omega[i, j] = \ (uy[i_p, j] - uy[i_n, j]) / (2.0 * dx) \ - (ux[i, j_p] - ux[i, j_n]) / (2.0 * dx)
def apply_force(velocities:ti.template(), colors:ti.template(), collisons:ti.template(), imp_data: ti.ext_arr()): f_strength = 10000.0 force_radius = n / 3.0 for i, j in velocities: omx, omy = imp_data[2], imp_data[3] mdir = ti.Vector([imp_data[0], imp_data[1]]) dx, dy = (i + 0.5 - omx), (j + 0.5 - omy) d2 = dx * dx + dy * dy # dv = F * dt factor = ti.exp(-d2 / force_radius) momentum = mdir * f_strength * dt * factor v = velocities[i, j] velocities[i, j] = v + momentum # add dye color = ti.Vector([1.0, 1.0, 1.0]) dc = colors[i, j] if mdir.norm() > 0.5: # dc += ti.exp(-d2 * (4 / (n / 15)**2)) * ti.Vector([imp_data[4], imp_data[5], imp_data[6]]) dc += ti.exp(-d2 * (4 / (n / 15)**2)) * color dc *= dye_decay colors[i, j] = dc if mdir.norm() > 0.5 and d2 < 50: collisons[i, j] = 1
def substep(): # 计算力和新的速度 # Compute force and new velocity n = num_particles[None] for i in range(n-1, -1, -1): v[i] *= ti.exp(-dt * damping[None]) # damping total_force = ti.Vector(gravity) * particle_mass # 初始受力只有重力 for j in range(n): # 对于互相连接的粒子用胡克定律计算力 if rest_length[i, j] != 0: x_ij = x[i] - x[j] total_force += -spring_stiffness[None] * ( x_ij.norm() - rest_length[i, j]) * x_ij.normalized() # 加上弹簧之间的力 v[i] += dt * total_force / particle_mass # 牛顿第二定律 # 碰撞地面 # Collide with ground for i in range(n): if x[i].y < bottom_y: x[i].y = bottom_y v[i].y = 0 # 计算新的位置 # Compute new position for i in range(num_particles[None]): x[i] += v[i] * dt
def init_level_set(self): sdf = ti.static(self.sign_dis.curr) inv_r = ti.static(4.0 / (self.resolution / 20.0)**2) for i, j in sdf: dx, dy = self.resolution / 2 - i, j d2 = dx * dx + dy * dy sdf[i, 0] = ti.exp(-d2 * inv_r) * 10.0
def collide(self, f, grid_pos, v_out, dt): dist = self.sdf(f, grid_pos) influence = min(ti.exp(-dist * self.softness[None]), 1) if (self.softness[None] > 0 and influence > 0.1) or dist <= 0: D = self.normal(f, grid_pos) collider_v_at_grid = self.collider_v(f, grid_pos, dt) input_v = v_out - collider_v_at_grid normal_component = input_v.dot(D) grid_v_t = input_v - min(normal_component, 0) * D grid_v_t_norm = length(grid_v_t) grid_v_t_friction = grid_v_t / grid_v_t_norm * max( 0, grid_v_t_norm + normal_component * self.friction[None]) flag = ti.cast( normal_component < 0 and ti.sqrt(grid_v_t.dot(grid_v_t)) > 1e-30, self.dtype) grid_v_t = grid_v_t_friction * flag + grid_v_t * (1 - flag) v_out = collider_v_at_grid + input_v * ( 1 - influence) + grid_v_t * influence #print(self.position[f], f) #print(grid_pos, collider_v, v_out, dist, self.friction, D) #if v_out[1] > 1000: #print(input_v, collider_v_at_grid, normal_component, D) return v_out
def affine(self, i): self.system.F[i] = (ti.Matrix.identity(ti.f32, DIM) + self.system.dt * self.system.C[i]) @ self.system.F[i] h = 0.3 if self.system.type[i] == 1 else ti.exp( 10 * (1.0 - self.system.Jp[i])) la = self.lambda_0 * h U, sig, V = ti.svd(self.system.F[i]) J = 1.0 for d in ti.static(range(DIM)): new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) if self.system.type[i] == 2 else sig[d, d] self.system.Jp[i] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if self.system.type[ i] == 0: # Reset deformation gradient to avoid numerical instability self.system.F[i] = ti.Matrix.identity(ti.f32, DIM) self.system.F[i][0, 0] = J elif self.system.type[i] == 2: self.system.F[i] = U @ sig @ V.transpose( ) # Reconstruct elastic deformation gradient after plasticity stress = ti.Matrix.identity(ti.f32, DIM) * la * J * (J - 1) if self.system.type[i] != 0: stress += 2 * self.mu_0 * h * ( self.system.F[i] - U @ V.transpose()) @ self.system.F[i].transpose() stress = (-self.system.dt * self.vol * 4 * self.inv_dx * self.inv_dx) * stress return stress + self.mass * self.system.C[i]
def substep(cur_x: ti.f32, cur_y: ti.f32, mag: ti.f32): # Compute force and new velocity n = num_particles[None] for i in range(n): v[i] *= ti.exp(-dt * damping[None]) # damping i2cur = [cur_x, cur_y] - x[i] total_force = i2cur.normalized() * mag * particle_mass for j in range(n): if rest_length[i, j] != 0: x_ij = x[i] - x[j] total_force += -spring_stiffness[None] * ( x_ij.norm() - rest_length[i, j]) * x_ij.normalized() v[i] += dt * total_force / particle_mass # Collide with boundary for i in range(n): if x[i].y < bottom: x[i].y = bottom v[i].y = -v[i].y if x[i].y > top: x[i].y = top v[i].y = -v[i].y if x[i].x < bottom: x[i].x = bottom v[i].x = -v[i].x if x[i].x > top: x[i].x = top v[i].x = -v[i].x # Compute new position for i in range(num_particles[None]): x[i] += v[i] * dt
def P2G(): # Particle to grid (P2G) for p in x: base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * inv_dx - base.cast(float) # Bspline w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update h = max(0.1, min(5, ti.exp(10 * (1.0 - Jp[p])))) # Hardening coefficient mu, la = mu_0 * h, lambda_0 * h mu = 0.0 U, sig, V = ti.svd(F[p]) J = 1.0 for d in ti.static(range(2)): new_sig = sig[d, d] if material[p] == 2: # snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # plasticity Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) # Reset deformation gradient stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose() + ti.Matrix.identity(float, 2) * la * J * (J - 1) stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress affine = stress + p_mass * C[p] for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid offset = ti.Vector([i, j]) dpos = (offset.cast(float) - fx) * dx weight = w[i][0] * w[j][1] grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) grid_m[base + offset] += weight * p_mass
def implicit(): n = num_particles[None] for i, j in ti.ndrange(n, n): M[i, j].fill(0) K[i, j].fill(0) A[i, j].fill(0) b[i].fill(0) for i in range(n): M[i, i][0, 0] = particle_mass M[i, i][1, 1] = particle_mass v[i] *= ti.exp(-dt * damping[None]) # damping for i, j in ti.ndrange(n, n): if rest_length[i, j] != 0: x_ij = x[j] - x[i] I = ti.Matrix([[1, 0], [0, 1]]) l = x_ij.norm() t = spring_stiffness[None] * (-I + rest_length[i, j] / l * (I - (x_ij @ x_ij.transpose() / (l * l)))) K[i, i] += t K[i, j] += -t for i, j in ti.ndrange(n, n): A[i, j] = (M[i, j] - dt * dt * K[i, j]) for i in range(n): b[i] = M[i, i] @ v[i] + dt * ti.Vector(gravity) * particle_mass for j in range(n): if rest_length[i, j] != 0: x_ij = x[i] - x[j] b[i] += -dt * spring_stiffness[None] * ( x_ij.norm() - rest_length[i, j]) * x_ij.normalized() for i in range(n): solve_v[i] = v[i]
def addRandomForce(dt: ti.f32): pos_p = ti.Vector([ti.random(), ti.random()]) F = ti.Vector([ti.random(), ti.random()]) * ti.random() * 1000.0 # if ti.random() > 0.01: # F.fill(0) for I in ti.grouped(u_old): u_old[I] += F * dt * ti.exp(-(I - pos_p).norm() / 0.1)
def substep(): # Compute force and new velocity n = num_particles[None] for i in range(n): v[i] *= ti.exp(-dt * damping[None]) # damping total_force = ti.Vector(gravity) * particle_mass for j in range(n): if rest_length[i, j] != 0: x_ij = x[i] - x[j] total_force += -spring_stiffness[None] * (x_ij.norm() - rest_length[i, j]) * x_ij.normalized() v[i] += dt * total_force / particle_mass # Collide with ground for i in range(n): if x[i].y < bottom_y: x[i].y = bottom_y v[i].y = 0 # Compute new position for i in range(num_particles[None]): x[i] += v[i] * dt df_ij(0,0) f_ij(0,0)
def electric_field(t: ti.f64): t_eff = t - t_h a = parameters[0] / (ti.sqrt(2 * np.pi) * parameters[1]) w = ti.sqr(parameters[1]) e = a * ti.exp(-ti.sqr(t_eff) / (2 * w)) * (ti.sin(parameters[2] * t_eff) + parameters[3] * ti.sin(parameters[4] * t_eff)) e_field[None] = e grad[0] = e / parameters[0] grad[1] = -e / parameters[1] + e * ti.sqr(t_eff) / (parameters[1]**3) grad[2] = a * ti.exp(-ti.sqr(t_eff) / (2 * w)) * ti.cos(parameters[2] * t_eff) * t_eff grad[3] = a * ti.exp(-ti.sqr(t_eff) / (2 * w)) * ti.sin(parameters[4] * t_eff) grad[4] = a * ti.exp(-ti.sqr(t_eff) / (2 * w)) * parameters[3] * ti.cos( parameters[4] * t_eff) * t_eff
def paint(t:ti.f32) : for i, j in pixels: p = ti.Vector([2*i-Width, 2*j-Height])/min(Width,Height) #background-color bcol = ti.Vector([1.0,0.8,0.7-0.07*p[1]]) * (1.0-0.25*p.norm()) #animate tt = mod(t, 1.5)/1.5 ss = pow(tt, 0.2)*0.5+0.5 ss = 1.0 + ss*0.5*ti.sin(tt*6.2831*3.0+p[1]*0.5)*ti.exp(-4.0*tt) p *= ti.Vector([0.5, 1.5]) + ss*ti.Vector([0.5, -0.5]) #shape p[1] -= 0.25 a = ti.atan2(p[0], p[1]) / 3.141593 r = p.norm() h = abs(a) d = (13.0*h - 22.0*h*h + 10.0*h*h*h)/(6.0-5.0*h) #color s = 0.75 + 0.75*p[0] s *= 1.0 - 0.4*r s = 0.3 + 0.7*s s *= 0.5 + 0.5*pow(1.0-clamp(r/d, 0.0, 1.0), 1.0) hcol = ti.Vector([1.0, 0.5*r, 0.3])*s pixels[i,j] = mix(bcol , hcol ,smoothstep(-0.01, 0.01, d-r))
def substep(): for i in ti.grouped(x): v[i] += gravity * dt for i in ti.grouped(x): force = ti.Vector([0.0, 0.0, 0.0]) for spring_offset in ti.static(spring_offsets): j = i + spring_offset if 0 <= j[0] < n and 0 <= j[1] < n: x_ij = x[i] - x[j] v_ij = v[i] - v[j] d = x_ij.normalized() current_dist = x_ij.norm() original_dist = quad_size * float(i - j).norm() # pylint: disable=no-member # Spring force force += -spring_Y * d * (current_dist / original_dist - 1) # Dashpot damping force += -v_ij.dot(d) * d * dashpot_damping * quad_size v[i] += force * dt for i in ti.grouped(x): v[i] *= ti.exp(-drag_damping * dt) offset_to_center = x[i] - ball_center[0] if offset_to_center.norm() <= ball_radius: # Velocity projection normal = offset_to_center.normalized() v[i] -= min(v[i].dot(normal), 0) * normal x[i] += dt * v[i]
def substep(): for i, j in ti.ndrange(n_grid, n_grid): grid_v[i, j] = [0, 0] grid_m[i, j] = 0 for p in range(n_particles): # Particle state update and scatter to grid (P2G) base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * inv_dx - base.cast(float) # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] w = [0.5 * ti.sqr(1.5 - fx), 0.75 - ti.sqr(fx - 1), 0.5 * ti.sqr(fx - 0.5)] F[p] = (ti.Matrix.identity(ti.f32, 2) + dt * C[p]) @ F[p] # deformation gradient update h = ti.exp(10 * (1.0 - Jp[p])) # Hardening coefficient: snow gets harder when compressed if material[p] == 1: # jelly, make it softer h = 0.3 mu, la = mu_0 * h, lambda_0 * h if material[p] == 0: # liquid mu = 0.0 U, sig, V = ti.svd(F[p]) J = 1.0 for d in ti.static(range(2)): new_sig = sig[d, d] if material[p] == 2: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if material[p] == 0: # Reset deformation gradient to avoid numerical instability F[p] = ti.Matrix.identity(ti.f32, 2) * ti.sqrt(J) elif material[p] == 2: F[p] = U @ sig @ V.T() # Reconstruct elastic deformation gradient after plasticity stress = 2 * mu * (F[p] - U @ V.T()) @ F[p].T() + ti.Matrix.identity(ti.f32, 2) * la * J * (J - 1) stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress affine = stress + p_mass * C[p] for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood offset = ti.Vector([i, j]) dpos = (offset.cast(float) - fx) * dx weight = w[i][0] * w[j][1] grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) grid_m[base + offset] += weight * p_mass for i, j in ti.ndrange(n_grid, n_grid): if grid_m[i, j] > 0: # No need for epsilon here grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity grid_v[i, j][1] -= dt * 50 # gravity if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 for p in range(n_particles): # grid to particle (G2P) base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * inv_dx - base.cast(float) w = [0.5 * ti.sqr(1.5 - fx), 0.75 - ti.sqr(fx - 1.0), 0.5 * ti.sqr(fx - 0.5)] new_v = ti.Vector.zero(ti.f32, 2) new_C = ti.Matrix.zero(ti.f32, 2, 2) for i, j in ti.static(ti.ndrange(3, 3)): # loop over 3x3 grid node neighborhood dpos = ti.Vector([i, j]).cast(float) - fx g_v = grid_v[base + ti.Vector([i, j])] weight = w[i][0] * w[j][1] new_v += weight * g_v new_C += 4 * inv_dx * weight * ti.outer_product(g_v, dpos) v[p], C[p] = new_v, new_C x[p] += dt * v[p] # advection
def sample(self, dir, N, t, i, j, mat_buf, mat_id): next_dir = ti.Vector([0.0, 0.0, 0.0]) w_out = dir cos_theta_i = w_out.dot(N) ior = UF.get_material_ior(mat_buf, mat_id) eta = ior probability = ti.random() f_or_b = 1.0 R = probability + 1.0 extinction = 1.0 if (cos_theta_i > 0.0): N = -N extinction = ti.exp(-0.1*t) else: cos_theta_i = -cos_theta_i eta = 1.0 /ior next_dir,suc = self.refract(w_out, N, eta) if suc > 0.0: R = self.schlick(cos_theta_i, ior) if (probability < R): next_dir = ts.reflect(w_out, N) else: f_or_b = -1.0 return next_dir, f_or_b*extinction
def hardening( dq, p ): # The amount of hardening depends on the amount of correction that occurred due to plasticity q_s[p] += dq phi = h0 + (h1 * q_s[p] - h3) * ti.exp(-h2 * q_s[p]) phi = phi / 180 * pi # details in Table. 3: Friction angle phi_F and hardening parameters h0, h1, and h3 are listed in degrees for convenience sin_phi = ti.sin(phi) alpha_s[p] = ti.sqrt(2 / 3) * (2 * sin_phi) / (3 - sin_phi)
def test_unary(): import time t = time.time() grad_test(lambda x: ti.sqrt(x), lambda x: np.sqrt(x)) grad_test(lambda x: ti.exp(x), lambda x: np.exp(x)) grad_test(lambda x: ti.log(x), lambda x: np.log(x)) ti.core.print_profile_info() print("Total time {:.3f}s".format(time.time() - t))
def init_gwei(): sum = -1.0 for i in self.gwei: x = i / self.radius y = ti.exp(-x**2) self.gwei[i] = y sum += y * 2 for i in self.gwei: self.gwei[i] /= sum
def particle_to_grid(): for k in particle_position: p = particle_position[k] grid = p * inv_dx base = int(grid - 0.5) fx = grid - base w = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2] # B-spline # stress = -dt * 4 * E * p_vol * (particle_J[k] - 1) * (inv_dx**2) # affine = ti.Matrix([[stress, 0], [0, stress]]) + p_mass * particle_C[k] particle_F[k] = (ti.Matrix.identity(float, 2) + dt * particle_C[k]) @ particle_F[k] # hardening coefficient h = ti.exp(10 * (1.0 - particle_J[k])) if particle_material[k] == 1: # jelly h = 0.3 mu, la = mu_0 * h, lambda_0 * h if particle_material[k] == 0: # fluid mu = 0.0 U, sig, V = ti.svd(particle_F[k]) J = 1.0 for d in ti.static(range(2)): new_sig = sig[d, d] if particle_material[k] == 2: # snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # plasticity particle_J[k] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if particle_material[ k] == 0: # Fluid: Reset deformation gradient to avoid numerical instability particle_F[k] = ti.Matrix.identity(float, 2) * ti.sqrt(J) elif particle_material[k] == 2: particle_F[k] = U @ sig @ V.transpose( ) # Snow: Reconstruct elastic deformation gradient after plasticity stress = 2 * mu * (particle_F[k] - U @ V.transpose()) @ particle_F[ k].transpose() + ti.Matrix.identity(float, 2) * la * J * (J - 1) stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress affine = stress + p_mass * particle_C[k] 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] dpos = (offset - fx) * dx grid_velocity[base + offset] += weight * ( p_mass * particle_velocity[k] + affine @ dpos) grid_weight[base + offset] += weight * p_mass
def accel(v: ti.template(), x: ti.template(), dt): for i in ti.grouped(x): acc = x[i] * 0 for d in ti.static(links): disp = x[tl.clamp(i + d, 0, tl.vec(*NN) - 1)] - x[i] dis = disp.norm() acc += disp * (dis - L) / L**2 v[i] += stiff * acc * dt v[i] *= ti.exp(-damp * dt)
def init_wei(): total = -1.0 for i in self.wei: x = i / self.radius r = ti.exp(-x**2) self.wei[i] = r total += r * 2 for i in self.wei: self.wei[i] /= total
def substep(n: ti.i32, t: ti.i32): # Compute force and new velocity for i in range(n): v[i] *= ti.exp(-dt * damping[None]) # damping total_force = ti.Vector( gravity) * particle_mass #gravity -> accelaration if actuation_type[i] == 1: #total_force = ti.Vector([9.8 * t, 0], real) * particle_mass total_force = ti.Vector(H_force) * particle_mass v[i] += dt * total_force / particle_mass
def p2g(f: ti.i32): for p in range(0, n_particles): new_Jp = Jp[f, p] base = ti.cast(x[f, p] * inv_dx - 0.5, ti.i32) fx = x[f, p] * inv_dx - ti.cast(base, ti.f32) w = [ 0.5 * ti.sqr(1.5 - fx), 0.75 - ti.sqr(fx - 1.0), 0.5 * ti.sqr(fx - 0.5) ] # quadratic kernels new_F = (ti.Matrix.diag(dim=dim, val=1) + dt * C[f, p]) @ F[f, p] # deformation gradient update h = max(0.1, min(5, ti.exp(10 * (1.0 - new_Jp)))) if particle_type[p] == 1: # jelly, make it softer h = 0.3 mu, la = mu_0 * h, lambda_0 * h if particle_type[p] == 0: # liquid mu = 0.0 U, sig, V = ti.svd(new_F) J = 1.0 for d in ti.static(range(2)): new_sig = sig[d, d] if particle_type[p] == 2: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity new_Jp *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if particle_type[ p] == 0: # Reset deformation gradient to avoid numerical instability new_F = ti.Matrix.diag(dim=dim, val=1) * ti.sqrt(J) elif particle_type[p] == 2: new_F = U @ sig @ ti.transposed( V) # Reconstruct elastic deformation gradient after plasticity F[f + 1, p] = new_F Jp[f + 1, p] = new_Jp stress = 2 * mu * (new_F - U @ ti.transposed(V)) @ ti.transposed( new_F) + ti.Matrix.diag(dim=dim, val=1) * la * J * (J - 1) stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress affine = stress + p_mass * C[f, p] # loop over 3x3 node neighborhood for i in ti.static(range(3)): for j in ti.static(range(3)): offset = ti.Vector([i, j]) dpos = (ti.cast(ti.Vector([i, j]), ti.f32) - fx) * dx weight = w[i](0) * w[j](1) ti.atomic_add(grid_v_in[base + offset], weight * (p_mass * v[f, p] + affine @ dpos)) ti.atomic_add(grid_m[base + offset], weight * p_mass)
def sampleScattering(u: ti.f32, maxDistance: ti.f32): # remap u to account for finite max distance ## f32 minU = ti.exp(-SIGMA * maxDistance) a = u * (1.0 - minU) + minU # sample with pdf proportional to exp(-sig*d) dist = -ti.log(a) / SIGMA pdf = SIGMA * a / (1.0 - minU) return (dist, pdf)
def apply_impulse(vf: ti.template(), dyef: ti.template(), imp_data: ti.ext_arr()): for i, j in vf: omx, omy = imp_data[2], imp_data[3] mdir = ti.Vector([imp_data[0], imp_data[1]]) dx, dy = (i + 0.5 - omx), (j + 0.5 - omy) d2 = dx * dx + dy * dy # dv = F * dt factor = ti.exp(-d2 / force_radius) momentum = mdir * f_strength * dt * factor v = vf[i, j] vf[i, j] = v + momentum # add dye dc = dyef[i, j] if mdir.norm() > 0.5: dc += ti.exp(-d2 * (4 / (res / 15)**2)) * ti.Vector( [imp_data[4], imp_data[5], imp_data[6]]) dc *= dye_decay dyef[i, j] = dc
def p2g(self, dt: ti.f32): for p in self.x: base = (self.x[p] * self.inv_dx - 0.5).cast(int) fx = self.x[p] * self.inv_dx - base.cast(float) # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] w = [ 0.5 * ti.sqr(1.5 - fx), 0.75 - ti.sqr(fx - 1), 0.5 * ti.sqr(fx - 0.5) ] # deformation gradient update self.F[p] = (ti.Matrix.identity(ti.f32, self.dim) + dt * self.C[p]) @ self.F[p] # Hardening coefficient: snow gets harder when compressed h = ti.exp(10 * (1.0 - self.Jp[p])) if self.material[ p] == self.material_elastic: # jelly, make it softer h = 0.3 mu, la = self.mu_0 * h, self.lambda_0 * h if self.material[p] == self.material_water: # liquid mu = 0.0 U, sig, V = ti.svd(self.F[p]) J = 1.0 for d in ti.static(range(self.dim)): new_sig = sig[d, d] #section 7 of snow paper ... dt being too big if self.material[p] == self.material_snow: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity self.Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if self.material[p] == self.material_water: # Reset deformation gradient to avoid numerical instability new_F = ti.Matrix.identity(ti.f32, self.dim) new_F[0, 0] = J self.F[p] = new_F elif self.material[p] == self.material_snow: # Reconstruct elastic deformation gradient after plasticity self.F[p] = U @ sig @ V.T() stress = 2 * mu * (self.F[p] - U @ V.T()) @ self.F[p].T( ) + ti.Matrix.identity(ti.f32, self.dim) * la * J * (J - 1) stress = (-dt * self.p_vol * 4 * self.inv_dx**2) * stress affine = stress + self.p_mass * self.C[p] # Loop over 3x3 grid node neighborhood for offset in ti.static(ti.grouped(self.stencil_range())): dpos = (offset.cast(float) - fx) * self.dx weight = 1.0 for d in ti.static(range(self.dim)): weight *= w[offset[d]][d] self.grid_v[base + offset] += weight * (self.p_mass * self.v[p] + affine @ dpos) self.grid_m[base + offset] += weight * self.p_mass