import taichi as ti import numpy as np ti.init( arch=ti.cuda) # Try to run on GPU, use ti.opengl if you don't have CUDA quality = 1 # Use a larger value for higher-res simulations n_particles, n_grid = 9000 * quality**2, 128 * quality dx, inv_dx = 1 / n_grid, float(n_grid) dt = 1e-4 / quality p_vol, p_rho = (dx * 0.5)**2, 1 p_mass = p_vol * p_rho E, nu = 5e3, 0.2 # Young's modulus and Poisson's ratio mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ( (1 + nu) * (1 - 2 * nu)) # Lame parameters x = ti.Vector(2, dt=ti.f32, shape=n_particles) # position v = ti.Vector(2, dt=ti.f32, shape=n_particles) # velocity C = ti.Matrix(2, 2, dt=ti.f32, shape=n_particles) # affine velocity field F = ti.Matrix(2, 2, dt=ti.f32, shape=n_particles) # deformation gradient material = ti.var(dt=ti.i32, shape=n_particles) # material id Jp = ti.var(dt=ti.f32, shape=n_particles) # plastic deformation grid_v = ti.Vector(2, dt=ti.f32, shape=(n_grid, n_grid)) # grid node momentum/velocity grid_m = ti.var(dt=ti.f32, shape=(n_grid, n_grid)) # grid node mass gravity = ti.Vector(2, dt=ti.f32, shape=()) attractor_strength = ti.var(dt=ti.f32, shape=()) attractor_pos = ti.Vector(2, dt=ti.f32, shape=()) @ti.kernel def substep():
# - [Homework 0 : Volumetric Clouds - GAMES201 高级物理引擎实战 - Taichi](https://forum.taichi.graphics/t/homework-0-volumetric-clouds/331) # by: neverfelly import taichi as ti import numpy as np import time ti.init(arch=ti.gpu) # res = 1280, 720 res = 320, 180 pixels = ti.Vector(3, dt=ti.f32, shape=res) sun_dir = ti.Vector([-1.0, 0.0, -1.0]) @ti.func def clamp(x): return ti.max(0, ti.min(1.0, x)) @ti.func def mod289(x): return x - ti.floor(x * (1.0 / 289.0)) * 289.0 @ti.func def perm(x): return mod289(((x * 34.0) + 1.0) * x)
import taichi as ti import numpy as np from enum import Enum ti.init(debug=True) MAX_NUM_ITEMS = 256 DT = 1e-1 NUM_ITEMS = ti.var(ti.i32, shape=()) CANVAS_SIZE = (512, 512) # 位置 P = ti.Vector(2, dt=ti.f32, shape=MAX_NUM_ITEMS) # 旋转角度 分别是角度, cos, sin值 R = ti.Vector(3, dt=ti.f32, shape=MAX_NUM_ITEMS) # 速度 V = ti.Vector(2, dt=ti.f32, shape=MAX_NUM_ITEMS) # 类型 0:圆, 1:长方形 TYPES = ti.var(dt=ti.u8, shape=MAX_NUM_ITEMS) # 参数, 对于圆是半径,对于长方形是长宽 PARAMS = ti.Vector(2, dt=ti.u16, shape=MAX_NUM_ITEMS) # 质量的倒数, 0表示Static IM = ti.var(dt=ti.f32, shape=MAX_NUM_ITEMS) # 转动惯量倒数 II = ti.var(dt=ti.f32, shape=MAX_NUM_ITEMS) GRAVITY = ti.Vector(2, dt=ti.f32, shape=())
from taichi.examples.patterns import taichi_logo import taichi as ti ti.init(arch=ti.vulkan) res = (512, 512) pixels = ti.Vector.field(3, dtype=float, shape=res) tex_format = ti.u8 texture = ti.Texture(tex_format, 1, (128, 128)) tex_ndarray = ti.ndarray(tex_format, shape=(128, 128)) @ti.kernel def make_texture(arr: ti.types.ndarray()): for i, j in ti.ndrange(128, 128): ret = taichi_logo(ti.Vector([i, j]) / 128) ret = ti.cast(ret * 255, ti.u8) arr[i, j] = ret make_texture(tex_ndarray) texture.from_ndarray(tex_ndarray) @ti.kernel def paint(t: ti.f32, tex: ti.types.texture(num_dimensions=2)): for i, j in pixels: uv = ti.Vector([i / res[0], j / res[1]]) warp_uv = uv + ti.Vector(
import taichi as ti import numpy as np ti.init(arch=ti.cuda) # Try to run on GPU. Use arch=ti.opengl on old GPUs quality = 1 # Use a larger value for higher-res simulations n_particles, n_grid = 9000 * quality**2, 128 * quality dx, inv_dx = 1 / n_grid, float(n_grid) dt = 1e-4 / quality p_vol, p_rho = (dx * 0.5)**2, 1 p_mass = p_vol * p_rho E, nu = 0.1e4, 0.2 # Young's modulus and Poisson's ratio mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ( (1 + nu) * (1 - 2 * nu)) # Lame parameters x = ti.Vector(2, dt=ti.f32, shape=n_particles) # position v = ti.Vector(2, dt=ti.f32, shape=n_particles) # velocity C = ti.Matrix(2, 2, dt=ti.f32, shape=n_particles) # affine velocity field F = ti.Matrix(2, 2, dt=ti.f32, shape=n_particles) # deformation gradient material = ti.var(dt=ti.i32, shape=n_particles) # material id Jp = ti.var(dt=ti.f32, shape=n_particles) # plastic deformation grid_v = ti.Vector(2, dt=ti.f32, shape=(n_grid, n_grid)) # grid node momentum/velocity grid_m = ti.var(dt=ti.f32, shape=(n_grid, n_grid)) # grid node mass @ti.kernel def substep(): for i, j in grid_m: grid_v[i, j] = [0, 0] grid_m[i, j] = 0 for p in x: # 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)
import taichi as ti import sys import math import numpy as np import os import taichi as tc import matplotlib.pyplot as plt real = ti.f32 ti.init(default_fp=real) max_steps = 2048 vis_interval = 64 output_vis_interval = 16 steps = 1024 assert steps * 2 <= max_steps vis_resolution = 1024 scalar = lambda: ti.var(dt=real) vec = lambda: ti.Vector(2, dt=real) loss = scalar() init_x = vec() init_v = vec() x = vec() x_inc = vec() # for TOI v = vec() impulse = vec()
import numblend as nb import taichi as ti import numpy as np import bpy nb.init() ti.init(arch=ti.cuda) #dim, n_grid, steps, dt = 2, 128, 20, 2e-4 #dim, n_grid, steps, dt = 2, 256, 32, 1e-4 dim, n_grid, steps, dt = 3, 32, 25, 4e-4 #dim, n_grid, steps, dt = 3, 64, 25, 2e-4 #dim, n_grid, steps, dt = 3, 128, 25, 8e-5 n_particles = n_grid**dim // 2**(dim - 1) dx = 1 / n_grid p_rho = 1 p_vol = (dx * 0.5)**2 p_mass = p_vol * p_rho gravity = 9.8 bound = 3 E = 400 x = ti.Vector.field(dim, float, n_particles) v = ti.Vector.field(dim, float, n_particles) C = ti.Matrix.field(dim, dim, float, n_particles) J = ti.field(float, n_particles) grid_v = ti.Vector.field(dim, float, (n_grid, ) * dim) grid_m = ti.field(float, (n_grid, ) * dim)
@ti.archs_support_sparse def benchmark_nested_struct_fill_and_clear(): a = ti.var(dt=ti.f32) N = 512 ti.root.pointer(ti.ij, [N, N]).dense(ti.ij, [8, 8]).place(a) @ti.kernel def fill(): for i, j in ti.ndrange(N * 8, N * 8): a[i, j] = 2.0 @ti.kernel def clear(): for i, j in a.parent(): ti.deactivate(a.parent().parent(), [i, j]) def task(): fill() clear() return ti.benchmark(task, repeat=30) ''' ti.init(arch=ti.cuda, enable_profiler=True) benchmark_nested_struct_fill_and_clear() ti.profiler_print() '''
import taichi as ti from display import display ti.init(default_fp = ti.f32, arch = ti.cpu) lx = 1.0 ly = 0.1 nx = 300 ny = 60 rho = 1 mu = 0.01 dx = lx / nx dy = ly / ny dt = 0.001 velo_rel = 0.01 p_rel = 0.03 # Add 1 cell padding to all directions. p = ti.field(dtype=ti.f32, shape=(nx + 2, ny + 2)) pcor = ti.field(dtype=ti.f32, shape=(nx + 2, ny + 2)) u = ti.field(dtype=ti.f32, shape=(nx + 3, ny + 2)) u0 = ti.field(dtype=ti.f32, shape=(nx + 3, ny + 2)) ucor = ti.field(dtype=ti.f32, shape=(nx + 3, ny + 2)) u_post = ti.field(dtype=ti.f32, shape=(nx + 2, ny + 2)) v = ti.field(dtype=ti.f32, shape=(nx + 2, ny + 3)) vcor = ti.field(dtype=ti.f32, shape=(nx + 2, ny + 3))
import taichi as ti import time ti.init(default_fp=ti.f64, arch=ti.cpu) n = 100 A = ti.field(dtype=ti.f64, shape=(n, n)) b = ti.field(dtype=ti.f64, shape=n) x = ti.field(dtype=ti.f64, shape=n) x_new = ti.field(dtype=ti.f64, shape=n) @ti.func 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
import taichi as ti import taichi_three as t3 from taichi_three.mciso import MCISO, Voxelizer import numpy as np ti.init(arch=ti.cuda) # can't use metal or opengl since sparse used in MCISO #dim, n_grid, steps, dt = 2, 128, 20, 2e-4 #dim, n_grid, steps, dt = 2, 256, 32, 1e-4 dim, n_grid, steps, dt = 3, 32, 25, 4e-4 #dim, n_grid, steps, dt = 3, 64, 25, 2e-4 #dim, n_grid, steps, dt = 3, 128, 25, 8e-5 n_particles = n_grid**dim // 2**(dim - 1) dx = 1 / n_grid print(f'n_particles={n_particles}') p_rho = 1 p_vol = (dx * 0.5)**2 p_mass = p_vol * p_rho gravity = 9.8 bound = 3 E = 400 x = ti.Vector.field(dim, float, n_particles) v = ti.Vector.field(dim, float, n_particles) C = ti.Matrix.field(dim, dim, float, n_particles) J = ti.field(float, n_particles) grid_v = ti.Vector.field(dim, float, (n_grid, ) * dim)
def wrapped(*test_args, **test_kwargs): for arch in archs: ti.init(arch=arch, **init_kwags) test(*test_args, **test_kwargs)
def init(self): for I in ti.grouped(ti.ndrange(*[self.N] * self.dim)): r_I = 5.0 for k in ti.static(range(self.dim)): r_I *= ti.cos(5 * math.pi * I[k] / self.N) self.init_r(I, r_I) @ti.kernel def paint(self): if ti.static(self.dim == 3): kk = self.N_tot * 3 // 8 for i, j in self.pixels: ii = int(i * self.N / self.N_gui) + self.N_ext jj = int(j * self.N / self.N_gui) + self.N_ext self.pixels[i, j] = self.x[ii, jj, kk] / self.N_tot def run(self, verbose=False): self.init() self.solve(max_iters=400, verbose=verbose) self.paint() ti.imshow(self.pixels) ti.print_kernel_profile_info() if __name__ == '__main__': ti.init(kernel_profiler=True) solver = MGPCG_Example() t = time.time() solver.run(verbose=True) print(f'Solver time: {time.time() - t:.3f} s')
# Tina is a real-time soft renderer based on Taichi for visualizing 3D scenes. # # To get started, let's try to load and display a monkey model in the GUI. import taichi as ti import tina ti.init(ti.gpu) # use GPU backend for better speed # to make tina actually display things, we need at least three things: # # 1. Scene - the top structure that manages all resources in the scene scene = tina.Scene() # 2. Model - the model to be displayed # # here we use `tina.MeshModel` which can load models from OBJ format files model = tina.MeshModel('assets/monkey.obj') # and, don't forget to add the model into the scene so that it gets displayed scene.add_object(model) # 3. GUI - we also need to create an window for display gui = ti.GUI('monkey') while gui.running: # update the camera transform from mouse events (will invoke gui.get_events) scene.input(gui) # render scene to image scene.render()
import taichi as ti import taichi_glsl as ts import taichi_three as t3 ti.init(ti.opengl) N = 12 dt = 0.01 scene = t3.SceneRT() camera = t3.Camera() scene.add_camera(camera) pos = ti.Vector(3, ti.f32, N) vel = ti.Vector(3, ti.f32, N) radius = ti.var(ti.f32, N) scene.add_ball(pos, radius) scene.set_light_dir([1, 1, -1]) @ti.kernel def init(): for i in pos: pos[i] = ts.randNDRange(ts.vec3(-1), ts.vec3(1)) vel[i] = ts.randNDRange(ts.vec3(-1.1), ts.vec3(1.1)) radius[i] = ts.randRange(0.1, 0.2) @ti.func def interact(i, j): disp = pos[i] - pos[j] disv = vel[i] - vel[j]
# This file is not part of standard tests since it uses too much GPU memory import taichi as ti ti.init(arch=ti.cuda, debug=True) res = 512 mask = ti.var(ti.i32) val = ti.var(ti.f32) ti.root.dense(ti.ijk, 512).place(mask) block = ti.root.pointer(ti.ijk, 128).dense(ti.ijk, 4) block.dense(ti.l, 128).place(val) @ti.kernel def load_inputs(): for i, j, k in mask: for l in range(128): val[i, j, k, l] = 1 load_inputs()
import taichi as ti import time from pytest import approx # TODO: make this a real benchmark and set up regression # TODO: merge this file into benchmark_reduction.py ti.init(arch=ti.gpu, print_ir=True, print_kernel_llvm_ir=True, kernel_profiler=True, print_kernel_llvm_ir_optimized=True) N = 1024 * 1024 * 128 a = ti.field(ti.f32, shape=N) @ti.kernel def fill(): ti.block_dim(128) for i in a: a[i] = 1.0 @ti.kernel def reduce() -> ti.f32: s = 0.0 ti.block_dim(1024) for i in a: s += a[i] return s
import taichi as ti import math ti.init(arch=ti.opengl) width = 660 height = 1000 pixels = ti.Vector(3, dt=ti.f32, shape=(width, height)) @ti.func def generatePoint(x, y, t): r = ti.random() nextX, nextY = 0.0, 0.0 if r < 0.01: nextX = 0 nextY = 0.16 * y elif r < 0.85: nextX = 0.85 * x + (0.04 + t) * y nextY = -(0.04 + t) * x + 0.85 * y + 1.6 elif r < 0.93: nextX = 0.20 * x + -0.26 * y nextY = 0.23 * x + 0.22 * y + 1.0 else: nextX = -0.15 * x + 0.28 * y nextY = 0.26 * x + 0.24 * y + 0.44 return nextX, nextY @ti.kernel
import taichi as ti import numpy as np import math ti.init(arch=ti.cpu) mat = np.array([[8, -3, 2], [4, 11, -1], [6, 3, 12]]) a = np.zeros(shape=3) b = np.array([20, 30, 36]) for iter in range(5): for i in range(3): temp = b[i] for j in range(3): if i != j: temp -= mat[i, j] * a[j] a[i] = temp / mat[i, i] print(a)
import taichi as ti import numpy as np import time # apply force after grid normalization (or explosion) # pressure in air cells should be 0 (or volume shrink quickly) # velocity in air cells may not be 0 # FIX: adjusted the boundary response in handle_boundary() and advect_particles(), is seems to be more energetic now # TODO: solve vorticity enhancement explosion problem ti.init(arch=ti.gpu, default_fp=ti.f32) res = 512 dt = 2e-2 #2e-3 #2e-2 substep = 1 rho = 1000 jacobi_iters = 500 jacobi_damped_para = 1 m_g = 128 n_grid = m_g * m_g n_particle = n_grid * 4 length = 10.0 dx = length / m_g inv_dx = 1 / dx # solid boundary
import taichi as ti import numpy as np import utils import math from engine.mpm_solver import MPMSolver write_to_disk = False ti.init(arch=ti.cuda) # Try to run on GPU gui = ti.GUI("Taichi MLS-MPM", res=512, background_color=0x112F41) mpm = MPMSolver(res=(128, 128), unbounded=True) mpm.add_surface_collider(point=(0, 0.0), normal=(0.3, 1), surface=mpm.surface_slip) for i in range(3): mpm.add_cube(lower_corner=[0.2 + i * 0.1, 0.3 + i * 0.1], cube_size=[0.1, 0.1], material=MPMSolver.material_elastic) for frame in range(500): mpm.step(8e-3) if frame < 100: mpm.add_cube(lower_corner=[0.1, 0.4], cube_size=[0.01, 0.05], velocity=[1, 0], material=MPMSolver.material_sand) if 10 < frame < 200: mpm.add_cube(lower_corner=[0.3, 0.7], cube_size=[0.2, 0.01],
import numpy as np import taichi as ti real = ti.f32 ti.init(default_fp=real, arch=ti.x64, kernel_profiler=True) # grid parameters N = 128 N_gui = 512 # gui resolution n_mg_levels = 4 pre_and_post_smoothing = 2 bottom_smoothing = 50 use_multigrid = True N_ext = N // 2 # number of ext cells set so that that total grid size is still power of 2 N_tot = 2 * N # setup sparse simulation data arrays r = [ti.field(dtype=real) for _ in range(n_mg_levels)] # residual z = [ti.field(dtype=real) for _ in range(n_mg_levels)] # M^-1 r x = ti.field(dtype=real) # solution p = ti.field(dtype=real) # conjugate gradient Ap = ti.field(dtype=real) # matrix-vector product alpha = ti.field(dtype=real) # step size beta = ti.field(dtype=real) # step size sum = ti.field(dtype=real) # storage for reductions pixels = ti.field(dtype=real, shape=(N_gui, N_gui)) # image buffer grid = ti.root.pointer(ti.ijk, [N_tot // 4]).dense(ti.ijk, 4).place(x, p, Ap)
import taichi as ti import taichi_glsl as ts import warnings ti.init() class MyAnimation(ts.Animation): def on_init(self): res = 512, 512 self.color = ts.Maccormack.make(lambda: ti.var(ti.f32, res)) self.vorts = ti.Vector(2, ti.f32, 4) self.vorty = ti.var(ti.f32, 4) self.circles = self.vorts self.circle_radius = 3 self.circle_color = 0x000000 self.img = self.color.new self.dt = 0.04 self.dx = 1 / res[0] self.define_input() @ti.func def velocity(self, P): p = P * self.dx vel = ts.vec2(0.0) for v in range(self.vorts.shape[0]): dis = (p - self.vorts[v]) dis = ts.normalizePow(dis, -1, 0.001) dis = dis.yx * ts.vec(-1, 1) * self.vorty[v] vel += dis return vel * 0.01
import taichi as ti import numpy as np ti.init(arch=ti.gpu) # Try to run on GPU quality = 1 # Use a larger value for higher-res simulations n_particles, n_grid = 9000 * quality**2, 128 * quality dx, inv_dx = 1 / n_grid, float(n_grid) dt = 1e-4 / quality p_vol, p_rho = (dx * 0.5)**2, 1 p_mass = p_vol * p_rho E, nu = 5e3, 0.2 # Young's modulus and Poisson's ratio mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ( (1 + nu) * (1 - 2 * nu)) # Lame parameters x = ti.Vector(2, dt=ti.f32, shape=n_particles) # position v = ti.Vector(2, dt=ti.f32, shape=n_particles) # velocity C = ti.Matrix(2, 2, dt=ti.f32, shape=n_particles) # affine velocity field F = ti.Matrix(2, 2, dt=ti.f32, shape=n_particles) # deformation gradient material = ti.var(dt=ti.i32, shape=n_particles) # material id Jp = ti.var(dt=ti.f32, shape=n_particles) # plastic deformation grid_v = ti.Vector(2, dt=ti.f32, shape=(n_grid, n_grid)) # grid node momentum/velocity grid_m = ti.var(dt=ti.f32, shape=(n_grid, n_grid)) # grid node mass gravity = ti.Vector(2, dt=ti.f32, shape=()) attractor_strength = ti.var(dt=ti.f32, shape=()) attractor_pos = ti.Vector(2, dt=ti.f32, shape=()) @ti.kernel def substep():
import taichi as ti import taichi_glsl as tl import taichi_three as t3 import numpy as np import math ti.init(ti.gpu) ### Parameters dt, beta, steps = 5e-3, 0, 12 #dt, beta, steps = 1e-2, 0.5, 5 beta_dt = beta * dt alpha_dt = (1 - beta) * dt jacobi_steps = 15 N = 128 NN = N, N W = 1 L = W / N gravity = 0.4 stiff = 20 damp = 2.6 ### Generic helpers x = ti.Vector(3, ti.f32, NN) v = ti.Vector(3, ti.f32, NN) b = ti.Vector(3, ti.f32, NN) F = ti.Vector(3, ti.f32, NN)
# This file has a kernel with 16 equal offloaded tasks. import taichi as ti ti.init(arch=ti.x64) quality = 1 # Use a larger value for higher-res simulations n_particles, n_grid = 9000 * quality**2, 128 * quality dx, inv_dx = 1 / n_grid, float(n_grid) dt = 1e-4 / quality p_vol, p_rho = (dx * 0.5)**2, 1 p_mass = p_vol * p_rho E, nu = 0.1e4, 0.2 # Young's modulus and Poisson's ratio mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ( (1 + nu) * (1 - 2 * nu)) # Lame parameters x = ti.Vector.field(2, ti.f32, shape=n_particles) # position v = ti.Vector.field(2, ti.f32, shape=n_particles) # velocity # affine velocity field C = ti.Matrix.field(2, 2, ti.f32, shape=n_particles) # deformation gradient F = ti.Matrix.field(2, 2, ti.f32, shape=n_particles) material = ti.field(dtype=int, shape=n_particles) # material id Jp = ti.field(ti.f32, shape=n_particles) # plastic deformation grid_v = ti.Vector.field(2, ti.f32, shape=(n_grid, n_grid)) # grid node momentum/velocity grid_m = ti.field(ti.f32, shape=(n_grid, n_grid)) # grid node mass @ti.kernel def substep(): for K in ti.static(range(4)): for p in x:
import math import time import random import numpy as np from plyfile import PlyData, PlyElement import os import utils from utils import create_output_folder from engine.mpm_solver import MPMSolver with_gui = True write_to_disk = False # Try to run on GPU ti.init(arch=ti.cuda, kernel_profiler=True, use_unified_memory=False, device_memory_fraction=0.7) max_num_particles = 400000 if with_gui: gui = ti.GUI("MLS-MPM", res=512, background_color=0x112F41) if write_to_disk: output_dir = create_output_folder('./sim') def visualize(particles): np_x = particles['position'] / 1.0 # simple camera transform
def test(*args, **kwargs): archs = [ti.core.host_arch()] for arch in archs: ti.init(arch=arch) func(*args, **kwargs)
import taichi as ti import taichi_three as t3 import numpy as np ti.init(ti.cpu) scene = t3.Scene() model = t3.Model(t3.Mesh.from_obj('assets/monkey.obj')) scene.add_model(model) camera = t3.Camera() scene.add_camera_d(camera) buffer = t3.GaussianBlur(t3.FrameBuffer(camera), 8) scene.add_buffer(buffer) light = t3.Light([0.4, -1.5, -0.8]) scene.add_light(light) gui = ti.GUI('Gaussian', camera.res) while gui.running: gui.get_event(None) gui.running = not gui.is_pressed(ti.GUI.ESCAPE) camera.from_mouse(gui) scene.render() gui.set_image(buffer.img) gui.show()
import taichi as ti arch = ti.vulkan if ti._lib.core.with_vulkan() else ti.cuda ti.init(arch=arch) N = 128 cell_size = 1.0 / N gravity = 0.5 stiffness = 1600 damping = 2 dt = 5e-4 ball_radius = 0.2 ball_center = ti.Vector.field(3, float, (1, )) x = ti.Vector.field(3, float, (N, N)) v = ti.Vector.field(3, float, (N, N)) num_triangles = (N - 1) * (N - 1) * 2 indices = ti.field(int, num_triangles * 3) vertices = ti.Vector.field(3, float, N * N) def init_scene(): for i, j in ti.ndrange(N, N): x[i, j] = ti.Vector([ i * cell_size, j * cell_size / ti.sqrt(2), (N - j) * cell_size / ti.sqrt(2) ]) ball_center[0] = ti.Vector([0.5, -0.5, -0.0])