1+ import taichi as ti
2+ ti.init(arch=ti.vulkan) # Alternatively, ti.init(arch=ti.cpu)
3+
4+ n = 128
5+ quad_size = 1.0 / n
6+ dt = 4e-2 / n
7+ substeps = int(1 / 60 // dt)
8+
9+ gravity = ti.Vector([0, -9.8, 0])
10+ spring_Y = 3e4
11+ dashpot_damping = 1e4
12+ drag_damping = 1
13+
14+ ball_radius = 0.3
15+ ball_center = ti.Vector.field(3, dtype=float, shape=(1, ))
16+ ball_center[0] = [0, 0, 0]
17+
18+ x = ti.Vector.field(3, dtype=float, shape=(n, n))
19+ v = ti.Vector.field(3, dtype=float, shape=(n, n))
20+
21+ num_triangles = (n - 1) * (n - 1) * 2
22+ indices = ti.field(int, shape=num_triangles * 3)
23+ vertices = ti.Vector.field(3, dtype=float, shape=n * n)
24+ colors = ti.Vector.field(3, dtype=float, shape=n * n)
25+
26+ bending_springs = False
27+
28+ @ti.kernel
29+ def initialize_mass_points():
30+ random_offset = ti.Vector([ti.random() - 0.5, ti.random() - 0.5]) * 0.1
31+
32+ for i, j in x:
33+ x[i, j] = [
34+ i * quad_size - 0.5 + random_offset[0], 0.6,
35+ j * quad_size - 0.5 + random_offset[1]
36+ ]
37+ v[i, j] = [0, 0, 0]
38+
39+
40+ @ti.kernel
41+ def initialize_mesh_indices():
42+ for i, j in ti.ndrange(n - 1, n - 1):
43+ quad_id = (i * (n - 1)) + j
44+ # 1st triangle of the square
45+ indices[quad_id * 6 + 0] = i * n + j
46+ indices[quad_id * 6 + 1] = (i + 1) * n + j
47+ indices[quad_id * 6 + 2] = i * n + (j + 1)
48+ # 2nd triangle of the square
49+ indices[quad_id * 6 + 3] = (i + 1) * n + j + 1
50+ indices[quad_id * 6 + 4] = i * n + (j + 1)
51+ indices[quad_id * 6 + 5] = (i + 1) * n + j
52+
53+ for i, j in ti.ndrange(n, n):
54+ if (i // 4 + j // 4) % 2 == 0:
55+ colors[i * n + j] = (0.22, 0.72, 0.52)
56+ else:
57+ colors[i * n + j] = (1, 0.334, 0.52)
58+
59+ initialize_mesh_indices()
60+
61+ spring_offsets = []
62+ if bending_springs:
63+ for i in range(-1, 2):
64+ for j in range(-1, 2):
65+ if (i, j) != (0, 0):
66+ spring_offsets.append(ti.Vector([i, j]))
67+
68+ else:
69+ for i in range(-2, 3):
70+ for j in range(-2, 3):
71+ if (i, j) != (0, 0) and abs(i) + abs(j) <= 2:
72+ spring_offsets.append(ti.Vector([i, j]))
73+
74+ @ti.kernel
75+ def substep():
76+ for i in ti.grouped(x):
77+ v[i] += gravity * dt
78+
79+ for i in ti.grouped(x):
80+ force = ti.Vector([0.0, 0.0, 0.0])
81+ for spring_offset in ti.static(spring_offsets):
82+ j = i + spring_offset
83+ if 0 <= j[0] < n and 0 <= j[1] < n:
84+ x_ij = x[i] - x[j]
85+ v_ij = v[i] - v[j]
86+ d = x_ij.normalized()
87+ current_dist = x_ij.norm()
88+ original_dist = quad_size * float(i - j).norm()
89+ # Spring force
90+ force += -spring_Y * d * (current_dist / original_dist - 1)
91+ # Dashpot damping
92+ force += -v_ij.dot(d) * d * dashpot_damping * quad_size
93+
94+ v[i] += force * dt
95+
96+ for i in ti.grouped(x):
97+ v[i] *= ti.exp(-drag_damping * dt)
98+ offset_to_center = x[i] - ball_center[0]
99+ if offset_to_center.norm() <= ball_radius:
100+ # Velocity projection
101+ normal = offset_to_center.normalized()
102+ v[i] -= min(v[i].dot(normal), 0) * normal
103+ x[i] += dt * v[i]
104+
105+ @ti.kernel
106+ def update_vertices():
107+ for i, j in ti.ndrange(n, n):
108+ vertices[i * n + j] = x[i, j]
109+
110+ window = ti.ui.Window("Taichi Cloth Simulation on GGUI", (1024, 1024),
111+ vsync=True)
112+ canvas = window.get_canvas()
113+ canvas.set_background_color((1, 1, 1))
114+ scene = ti.ui.Scene()
115+ camera = ti.ui.make_camera()
116+
117+ current_t = 0.0
118+ initialize_mass_points()
119+
120+ while window.running:
121+ if current_t > 1.5:
122+ # Reset
123+ initialize_mass_points()
124+ current_t = 0
125+
126+ for i in range(substeps):
127+ substep()
128+ current_t += dt
129+ update_vertices()
130+
131+ camera.position(0.0, 0.0, 3)
132+ camera.lookat(0.0, 0.0, 0)
133+ scene.set_camera(camera)
134+
135+ scene.point_light(pos=(0, 1, 2), color=(1, 1, 1))
136+ scene.ambient_light((0.5, 0.5, 0.5))
137+ scene.mesh(vertices,
138+ indices=indices,
139+ per_vertex_color=colors,
140+ two_sided=True)
141+
142+ # Draw a smaller ball to avoid visual penetration
143+ scene.particles(ball_center, radius=ball_radius * 0.95, color=(0.5, 0.42, 0.8))
144+ canvas.scene(scene)
145+ window.show()
0 commit comments