├── .idea ├── .gitignore ├── PNCG_open.iml ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── README.md ├── algorithm ├── base_deformer.py ├── collision_detection.py ├── collision_detection_v2.py ├── newton_matrix_free_pcg.py ├── newton_sparse_solver.py ├── pncg_base_collision_free.py └── pncg_base_ipc.py ├── demo ├── PNCG_supplemental_document.pdf ├── cubic_demos.py ├── demo_low_res.mp4 ├── drag_armadillo_demo.py ├── n_E_demo.py ├── squeeze_armadillo_demo.py ├── twist_demo.py └── unittest_demos.py ├── math_utils ├── cubic_roots.py ├── elastic_util.py ├── graphic_util.py ├── matrix_util.py └── matrix_util_tmp.py ├── model └── mesh │ ├── Armadillo13K │ ├── Armadillo13K.ele │ ├── Armadillo13K.face │ ├── Armadillo13K.node │ └── is_dirichlet.npy │ ├── banana │ ├── banana.edge │ ├── banana.ele │ ├── banana.face │ ├── banana.node │ └── banana.obj │ ├── cliff │ ├── cliff.edge │ ├── cliff.ele │ ├── cliff.face │ └── cliff.node │ ├── crack │ ├── crack.edge │ ├── crack.ele │ ├── crack.face │ └── crack.node │ ├── cube │ ├── cube.edge │ ├── cube.ele │ ├── cube.face │ ├── cube.node │ └── is_dirichlet.npy │ ├── cube_10 │ ├── cube_10.edge │ ├── cube_10.ele │ ├── cube_10.face │ ├── cube_10.node │ └── is_dirichlet.npy │ ├── cube_2 │ ├── cube_2.ele │ └── cube_2.node │ ├── cube_20 │ ├── cube_20.edge │ ├── cube_20.ele │ ├── cube_20.face │ ├── cube_20.node │ └── is_dirichlet.npy │ ├── cube_40 │ ├── cube_40.edge │ ├── cube_40.ele │ ├── cube_40.face │ ├── cube_40.node │ └── is_dirichlet.npy │ ├── cube_6 │ ├── cube_6.edge │ ├── cube_6.ele │ ├── cube_6.face │ └── cube_6.node │ ├── cube_8 │ ├── cube_8.edge │ ├── cube_8.ele │ ├── cube_8.face │ └── cube_8.node │ ├── e_2 │ ├── e_2.edge │ ├── e_2.ele │ ├── e_2.face │ └── e_2.node │ ├── hole │ ├── hole.edge │ ├── hole.ele │ ├── hole.face │ └── hole.node │ ├── internal_edges │ ├── internal_edges.edge │ ├── internal_edges.ele │ ├── internal_edges.face │ └── internal_edges.node │ ├── mat150x150t40_new │ ├── is_dirichlet.npy │ ├── mat150x150t40_new.ele │ ├── mat150x150t40_new.face │ └── mat150x150t40_new.node │ ├── rod300x33 │ ├── is_dirichlet.npy │ ├── rod300x33.ele │ ├── rod300x33.face │ └── rod300x33.node │ ├── spike │ ├── spike.edge │ ├── spike.ele │ ├── spike.face │ └── spike.node │ ├── tet │ ├── tet.ele │ └── tet.node │ └── wedge │ ├── wedge.edge │ ├── wedge.ele │ ├── wedge.face │ └── wedge.node ├── others └── Paper介绍.pdf ├── requirements.txt ├── siggraphconferencepapers24-96_camera.pdf └── util ├── logger.py ├── model_loading.py ├── sympy_dfdx.py └── timer.py /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/PNCG_open.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository hosts the official implementation of the paper [Preconditioned Nonlinear Conjugate Gradient Method for Real-time Interior-point Hyperelasticity](https://xingbaji.github.io/PNCG_project_page/). 2 | 3 | ### Run demo 4 | Requirements: 5 | ```pip install -r requirements.txt``` 6 | 7 | Run: 8 | ``` 9 | cd PNCG_IPC/demo 10 | python cubic_demos 11 | ``` 12 | 13 | ### Project Structure 14 | The repository is organized as follows: 15 | 16 | - algorithm/: Contains core algorithms, infrastructure, and functions critical to our method. 17 | The workflow starts with base_deformer, progresses through collision_detection_v2, and finally integrates within pncg_base_ipc. 18 | 19 | - demo/: A collection of demonstrations showcasing the capabilities and performance of our method. 20 | 21 | - util/model_loading: Contains code for loading models necessary for our demonstrations and tests. 22 | 23 | - math_utils/: Hosts essential utility functions for elastic deformations, primarily within elastic_util.py and matrix_util.py. 24 | 25 | - model/: Stores model files utilized in the demonstrations and testing phases. 26 | 27 | ### Note 28 | - The newest version of Numpy may cause Core Dumped, I don't figure out why it happens. It seems to due to the version difference of meshtaichi package and Numpy. Older version such as numpy1.26, is fine. 29 | - When using MeshTaichi to load a model, the xxxx.face file is necessary, while the face information is not required. So some .face files contain just one face. 30 | Or You can just delete following code in \_\_init\_\_.py in meshtaichi_patcher 31 | ``` 32 | ans["face"] = read_tetgen(f'{base_name}.face')[0].reshape(-1, 3) 33 | ``` 34 | - Please run in linux system, the performance of our code in windows is worse than linux. 35 | - Feel free to contact me at shenxing03@corp.netease.com / shenxingsx@zju.edu.cn or create a Github issue if you have questions regarding setting up the repository, running examples or adding new examples. 36 | - A introduction of our paper can be found at others/Paper介绍.pdf. 37 | 38 | ### Citation 39 | Please consider citing our paper if your find our research or this codebase helpful: 40 | 41 | @inproceedings{10.1145/3641519.3657490, 42 | author = {Shen, Xing and Cai, Runyuan and Bi, Mengxiao and Lv, Tangjie}, 43 | title = {Preconditioned Nonlinear Conjugate Gradient Method for Real-time Interior-point Hyperelasticity}, 44 | year = {2024}, 45 | isbn = {9798400705250}, 46 | publisher = {Association for Computing Machinery}, 47 | address = {New York, NY, USA}, 48 | url = {https://doi.org/10.1145/3641519.3657490}, 49 | doi = {10.1145/3641519.3657490}, 50 | booktitle = {ACM SIGGRAPH 2024 Conference Papers}, 51 | articleno = {96}, 52 | numpages = {11}, 53 | keywords = {GPU, Nonlinear conjugate gradient method, Physics-based simulation}, 54 | location = {Denver, CO, USA}, 55 | series = {SIGGRAPH '24} 56 | } 57 | -------------------------------------------------------------------------------- /algorithm/base_deformer.py: -------------------------------------------------------------------------------- 1 | import imageio 2 | from math_utils.elastic_util import * 3 | from util.logger import * 4 | from util.model_loading import * 5 | 6 | @ti.data_oriented 7 | class base_deformer: 8 | def __init__(self, demo): 9 | #set physical paramters 10 | model = model_loading(demo=demo) 11 | self.demo = demo 12 | print('demo', self.demo) 13 | self.mu, self.la = model.mu, model.la 14 | self.dict = model.dict 15 | self.density = model.density 16 | self.dt = model.dt 17 | self.gravity = model.gravity 18 | self.ground = model.ground 19 | self.frame = 0 20 | self.camera_position = model.camera_position 21 | self.camera_lookat = model.camera_lookat 22 | self.mesh = model.mesh 23 | 24 | self.mesh.verts.place({'x': ti.math.vec3, 25 | 'v': ti.math.vec3, 26 | 'm': float}) 27 | 28 | self.mesh.cells.place({'B': ti.math.mat3, 29 | 'W': float}) 30 | self.mesh.verts.x.from_numpy(self.mesh.get_position_as_numpy()) 31 | self.mesh.verts.v.fill([0.0, 0.0, 0.0]) 32 | print('load mesh finish') 33 | self.precompute() 34 | print('precompute finish') 35 | self.indices = ti.field(ti.u32, shape=len(self.mesh.cells) * 4 * 3) 36 | self.init_indices() 37 | print('init indice finish') 38 | self.assign_elastic_type(model.elastic_type) 39 | self.set_point_lights() 40 | 41 | def assign_elastic_type(self,elastic): 42 | #set elastic type 43 | if elastic=='ARAP': # as rigig as possible 44 | self.compute_Psi = compute_Psi_ARAP 45 | self.compute_dPsidx = compute_dPsidx_ARAP # dPsidx = \frac{\partial \PSi}{\partial x} 46 | self.compute_diag_d2Psidx2 = compute_diag_d2Psidx2_ARAP # d2Psidx2 is \frac{\partial^2 \PSi}{\partial x^2} 47 | self.compute_p_d2Psidx2_p = compute_pHp_ARAP 48 | elif elastic == 'SNH': # stable neo-hookean 49 | self.compute_Psi = compute_Psi_SNH 50 | self.compute_dPsidx = compute_dPsidx_SNH 51 | self.compute_diag_d2Psidx2 = compute_diag_d2Psidx2_SNH 52 | self.compute_p_d2Psidx2_p = compute_pHp_SNH 53 | elif elastic=='ARAP_filter': 54 | # ARAP_filter: filter the eigen value to make the hessian matrix spd 55 | self.compute_Psi = compute_Psi_ARAP 56 | self.compute_dPsidx = compute_dPsidx_ARAP 57 | self.compute_diag_d2Psidx2 = compute_diag_d2Psidx2_ARAP_filter 58 | self.compute_p_d2Psidx2_p = compute_pHp_ARAP_filter 59 | elif elastic=='FCR': # fixed corotated 60 | self.compute_Psi = compute_Psi_FCR 61 | self.compute_dPsidx = compute_dPsidx_FCR 62 | self.compute_diag_d2Psidx2 = compute_diag_d2Psidx2_FCR 63 | self.compute_p_d2Psidx2_p = compute_pHp_FCR 64 | elif elastic=='FCR_filter': # fixed corotated with filterd ARAP eigen value 65 | self.compute_Psi = compute_Psi_FCR 66 | self.compute_dPsidx = compute_dPsidx_FCR 67 | self.compute_diag_d2Psidx2 = compute_diag_d2Psidx2_FCR_filter 68 | self.compute_p_d2Psidx2_p = compute_pHp_FCR_filter 69 | elif elastic == 'NH': # neo-hookean 70 | self.compute_Psi = compute_Psi_NH 71 | self.compute_dPsidx = compute_dPsidx_NH 72 | self.compute_diag_d2Psidx2 = compute_diag_d2Psidx2_NH 73 | self.compute_p_d2Psidx2_p = compute_pHp_NH 74 | else: 75 | print('Wrong elastic type') 76 | 77 | def step(self): 78 | pass 79 | 80 | @ti.kernel 81 | def precompute(self): 82 | for c in self.mesh.cells: 83 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1,4))]) 84 | c.B = Ds.inverse() 85 | c.W = ti.abs(Ds.determinant()) / 6.0 86 | for i in ti.static(range(4)): 87 | c.verts[i].m += self.density * c.W / 4.0 88 | 89 | @ti.kernel 90 | def init_indices(self): 91 | for c in self.mesh.cells: 92 | ind = [[0, 2, 1], [0, 3, 2], [0, 1, 3], [1, 2, 3]] 93 | for i in ti.static(range(4)): 94 | for j in ti.static(range(3)): 95 | self.indices[(c.id * 4 + i) * 3 + j] = c.verts[ind[i][j]].id 96 | 97 | 98 | def save_results(self, n_frames=300, SAVE_OBJ=False, SAVE_PNG=True): 99 | import json 100 | import time 101 | window = ti.ui.Window("visual fem", (800, 600), show_window=False) 102 | canvas = window.get_canvas() 103 | scene = ti.ui.Scene() 104 | camera = ti.ui.Camera() 105 | camera.position(self.camera_position[0], self.camera_position[1], self.camera_position[2]) 106 | camera.lookat(self.camera_lookat[0], self.camera_lookat[1], self.camera_lookat[2]) 107 | camera.fov(75) 108 | dir = '../demo_results/final/' + self.demo + '/' 109 | img_dir = dir+'imgs/' 110 | obj_dir = dir+'objs/' 111 | if not os.path.exists(img_dir): 112 | os.makedirs(img_dir) 113 | os.makedirs(obj_dir) 114 | with open(dir + 'config.json', 'w') as f: 115 | json.dump(self.config, f) 116 | writer = imageio.get_writer(os.path.join(dir, self.demo+'.gif'), duration=10) 117 | canvas.set_background_color(color=(0.2, 0.2, 0.2)) 118 | point_light_color = (1.0, 0.9, 0.8) # Warm white color 119 | diffuse_color = (0.6, 0.4, 0.2) 120 | Times = [] 121 | Iters = [] 122 | self.step() 123 | with Logger(dir + f'log.txt'): 124 | for i in range(n_frames): 125 | tic = time.time() 126 | step_iters = self.step() 127 | toc = time.time() 128 | step_time = toc - tic 129 | print('Time', step_time, 'FPS', 1.0 / step_time) 130 | Times.append(step_time) 131 | Iters.append(step_iters) 132 | if SAVE_OBJ == True: 133 | self.save_obj(obj_dir) 134 | if SAVE_PNG == True: 135 | scene.set_camera(camera) 136 | scene.ambient_light((0.1, 0.1, 0.1)) 137 | for light_pos in self.point_lights: 138 | scene.point_light(pos=light_pos, color=point_light_color) 139 | scene.mesh_instance(self.mesh.verts.x, self.indices, show_wireframe=False, 140 | color=diffuse_color) 141 | canvas.scene(scene) 142 | filename = f'{self.frame:05d}.png' 143 | save_path = os.path.join(img_dir, filename) 144 | window.save_image(save_path) 145 | writer.append_data(imageio.v3.imread(save_path)) 146 | print(filename, 'saved') 147 | average_time = sum(Times) / len(Times) 148 | print('average time', average_time, 'average FPS', 1.0 / average_time) 149 | print('times', Times) 150 | FPS = [1.0 / t for t in Times] 151 | print('FPS', FPS) 152 | print('Iters', Iters) 153 | writer.close() 154 | from matplotlib import pyplot as plt 155 | plt.figure() 156 | plt.plot(Times, label='Time') 157 | plt.savefig(dir + f'times.png') 158 | plt.close() 159 | plt.figure() 160 | plt.plot(Iters, label='Iters') 161 | plt.savefig(dir + f'iters.png') 162 | plt.close() 163 | plt.figure() 164 | plt.plot(FPS, label='FPS') 165 | plt.savefig(dir + f'FPS.png') 166 | plt.close() 167 | 168 | def convert_pngs2gif(self,path): 169 | writer = imageio.get_writer(os.path.join(path, self.demo+'.gif'), duration=10) 170 | for file in os.listdir(path): 171 | if file.endswith('.png'): 172 | writer.append_data(imageio.v3.imread(file)) 173 | writer.close() 174 | print('gifs saved') 175 | 176 | def save_obj(self,obj_dir, rate = 1): 177 | if self.frame % rate == 0: 178 | x_np = self.mesh.verts.x.to_numpy() 179 | boundary_triangles_np = self.boundary_triangles.to_numpy() 180 | directory = obj_dir 181 | if not os.path.exists(directory): 182 | os.makedirs(directory) 183 | f = open(directory + f'{self.frame:03d}.obj', 'w') 184 | for i in range(self.n_verts): 185 | f.write('v %.6f %.6f %.6f\n' % (x_np[i, 0] , x_np[i, 1] , x_np[i, 2] )) 186 | for [p0, p1, p2] in boundary_triangles_np: 187 | f.write('f %d %d %d\n' % (p0 + 1, p1 + 1, p2 + 1)) 188 | f.close() 189 | v_np = self.mesh.verts.v.to_numpy() 190 | np.save(directory + f'x{self.frame:03d}.npy', x_np) 191 | np.save(directory + f'v{self.frame:03d}.npy', v_np) 192 | 193 | def load_frame(self, path, frame): 194 | self.frame = frame 195 | print(f'x{frame:03d}.npy') 196 | x_np = np.load(path + f'x{frame:03d}.npy') 197 | v_np = np.load(path + f'v{frame:03d}.npy') 198 | self.mesh.verts.x.from_numpy(x_np) 199 | self.mesh.verts.v.from_numpy(v_np) 200 | 201 | def restart(self): 202 | self.mesh.verts.x.copy_from(self.mesh.verts.x_init) 203 | self.mesh.verts.v.fill(0) 204 | self.frame = 0 205 | 206 | @ti.kernel 207 | def init_v(self,v:float): 208 | for vert in self.mesh.verts: 209 | vert.v[1] = v 210 | 211 | def set_point_lights(self, num_lights=6, light_distance=1.5): 212 | node_np = self.mesh.get_position_as_numpy() 213 | node_center = np.mean(node_np, axis=0) 214 | node_extents = np.max(node_np, axis=0) - np.min(node_np, axis=0) 215 | max_extent = np.max(node_extents) 216 | 217 | self.point_lights = [] 218 | for i in range(num_lights): 219 | # Calculate spherical coordinates 220 | theta = np.pi * (1.0 + 2 * i / num_lights) 221 | phi = np.arccos(-1.0 + 2 * i / num_lights) 222 | 223 | # Convert to Cartesian coordinates 224 | x = light_distance * max_extent * np.sin(phi) * np.cos(theta) 225 | y = light_distance * max_extent * np.sin(phi) * np.sin(theta) 226 | z = light_distance * max_extent * np.cos(phi) 227 | 228 | # Offset from the center of the mesh 229 | light_position = node_center + np.array([x, y, z]) 230 | self.point_lights.append(light_position) 231 | 232 | 233 | def visual(self): 234 | print('precombile') 235 | self.step() 236 | print('precombile finish') 237 | window = ti.ui.Window("Visualization", (800, 600), vsync=True) 238 | dir = '../demo_results/final/' + self.demo + '/' 239 | if not os.path.exists(dir): 240 | os.makedirs(dir) 241 | canvas = window.get_canvas() 242 | scene = ti.ui.Scene() 243 | camera = ti.ui.Camera() 244 | camera.position(self.camera_position[0], self.camera_position[1], self.camera_position[2]) 245 | camera.lookat(self.camera_lookat[0], self.camera_lookat[1], self.camera_lookat[2]) 246 | camera.fov(75) 247 | canvas.set_background_color(color=(0.2, 0.2, 0.2)) 248 | point_light_color = (1.0, 0.9, 0.8) # Warm white color 249 | diffuse_color = (0.6, 0.4, 0.2) 250 | while window.running: 251 | if window.get_event(ti.ui.PRESS): 252 | if window.event.key == 'r': 253 | self.restart() 254 | if window.event.key == 'b': 255 | break 256 | camera.track_user_inputs(window, movement_speed=0.1, hold_key=ti.ui.RMB) 257 | scene.set_camera(camera) 258 | scene.ambient_light((0.1, 0.1, 0.1)) 259 | for light_pos in self.point_lights: 260 | scene.point_light(pos=light_pos, color=point_light_color) 261 | scene.mesh_instance(self.mesh.verts.x, self.indices, show_wireframe=False, 262 | color=diffuse_color) 263 | canvas.scene(scene) 264 | window.show() 265 | self.step() 266 | 267 | -------------------------------------------------------------------------------- /algorithm/newton_matrix_free_pcg.py: -------------------------------------------------------------------------------- 1 | # My implement of newton PCG solver 2 | # Sometime it would cause nan? 3 | 4 | import numpy as np 5 | np.set_printoptions(suppress=True) 6 | from algorithm.base_deformer import * 7 | from util.model_loading import * 8 | 9 | 10 | @ti.data_oriented 11 | class newton_base_deformer(base_deformer): 12 | def __init__(self, demo): 13 | model = model_loading(demo=demo) 14 | self.demo = demo 15 | print('demo', self.demo) 16 | self.dict = model.dict 17 | self.mu, self.la = model.mu, model.la 18 | print('mu', self.mu, 'la', self.la) 19 | self.density = model.density 20 | self.dt = model.dt 21 | self.gravity = model.gravity 22 | self.ground = model.ground 23 | print('ground', self.ground) 24 | self.mesh = model.mesh 25 | self.ground = model.ground 26 | self.frame = 0 27 | self.epsilon = model.epsilon 28 | self.iter_max = model.iter_max 29 | self.camera_position = model.camera_position 30 | self.camera_lookat = model.camera_lookat 31 | self.SMALL_NUM = 1e-7 32 | # initialize model 33 | self.mesh.verts.place({'x': ti.types.vector(3, float), 34 | 'v': ti.types.vector(3, float), 35 | 'm': float, 36 | 'x_n': ti.types.vector(3, float), 37 | 'x_hat': ti.types.vector(3, float), 38 | 'x_prev': ti.types.vector(3, float), 39 | 'x_init': ti.types.vector(3, float), 40 | 'grad': ti.types.vector(3, float), 41 | 'delta_x': ti.math.vec3, 42 | 'diagH': ti.math.vec3, 43 | 'mul_ans': ti.math.vec3, # Ax 44 | 'b': ti.math.vec3, 45 | 'r': ti.math.vec3, 46 | 'd': ti.math.vec3, 47 | 'q': ti.math.vec3, 48 | 'tmp': ti.math.vec3 49 | }) 50 | 51 | self.mesh.cells.place({'B': ti.math.mat3, 'W': float}) 52 | self.mesh.verts.x.from_numpy(self.mesh.get_position_as_numpy()) 53 | self.mesh.verts.x_init.copy_from(self.mesh.verts.x) 54 | self.n_verts = self.mesh._vert_position.shape[0] 55 | self.n_cells = len(self.mesh.cells) 56 | print('n_verts,n_cells', self.n_verts, self.n_cells) 57 | 58 | # precompute 59 | self.precompute() 60 | self.indices = ti.field(ti.i32, shape=len(self.mesh.cells) * 4 * 3) 61 | self.init_indices() 62 | self.assign_elastic_type(model.elastic_type) 63 | self.set_point_lights() 64 | self.config = model.dict 65 | 66 | @ti.kernel 67 | def assign_xn_xhat(self): 68 | ti.mesh_local(self.mesh.verts.x) 69 | for vert in self.mesh.verts: 70 | vert.x_n = vert.x 71 | vert.x_hat = vert.x + self.dt * vert.v 72 | vert.x_hat[1] += self.dt * self.dt * self.gravity 73 | 74 | @ti.kernel 75 | def compute_E(self) -> float: 76 | E = 0.0 77 | ti.mesh_local(self.mesh.verts.x) 78 | for vert in self.mesh.verts: 79 | E += 0.5 * vert.m * (vert.x - vert.x_hat).norm_sqr() 80 | for c in self.mesh.cells: 81 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 82 | F = Ds @ c.B 83 | Psi = compute_Psi_ARAP(F,self.mu,self.la) 84 | E += (self.dt ** 2) * c.W * Psi 85 | return E 86 | 87 | @ti.kernel 88 | def mul_operation(self): 89 | for vert in self.mesh.verts: 90 | vert.mul_ans = vert.m * vert.tmp 91 | for c in self.mesh.cells: 92 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 93 | B = c.B 94 | F = Ds @ B 95 | dFdx = compute_dFdx(B) # 9x12 96 | para = self.dt ** 2 * c.W 97 | d2PsidF2 = compute_d2PsidF2_ARAP_filter(F, self.mu, self.la) 98 | d2Psidx2 = (dFdx.transpose()) @ d2PsidF2 @ dFdx # 12x12 99 | d2Psidx2_tmp = para * d2Psidx2 100 | Tmp = ti.Vector.zero(float, 12) 101 | Tmp[0:3] = c.verts[0].tmp 102 | Tmp[3:6] = c.verts[1].tmp 103 | Tmp[6:9] = c.verts[2].tmp 104 | Tmp[9:12] = c.verts[3].tmp 105 | mul_res = d2Psidx2_tmp @ Tmp 106 | for i in range(4): 107 | for j in range(3): 108 | c.verts[i].mul_ans[j] += mul_res[3*i+j] 109 | 110 | @ti.kernel 111 | def compute_grad_and_diagH(self): 112 | for vert in self.mesh.verts: 113 | vert.grad = vert.m * (vert.x - vert.x_hat) 114 | vert.diagH = vert.m * ti.Vector.one(float, 3) 115 | # ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.x, self.mesh.verts.diagH) 116 | for c in self.mesh.cells: 117 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 118 | B = c.B 119 | F = Ds @ B # 3x3 120 | para = c.W * self.dt ** 2 121 | dPsidx = para * compute_dPsidx_ARAP(F, B, self.mu, self.la) 122 | diagH_d2Psidx2 = para * compute_diag_d2Psidx2_ARAP_filter(F, B, self.mu, self.la) 123 | for i in range(4): 124 | c.verts[i].grad += ti.Vector([dPsidx[3 * i], dPsidx[3 * i +1], dPsidx[3 * i + 2]], float) 125 | tmp = ti.Vector([diagH_d2Psidx2[3 * i], diagH_d2Psidx2[3 * i + 1], diagH_d2Psidx2[3 * i + 2]]) 126 | tmp = ti.max(tmp ,0.0) 127 | c.verts[i].diagH += tmp 128 | 129 | @ti.kernel 130 | def compute_delta_x_inf_norm(self) -> float: 131 | ret = 0.0 132 | for vert in self.mesh.verts: 133 | ti.atomic_max(ret, (ti.abs(vert.delta_x)).max()) 134 | return ret 135 | 136 | @ti.kernel 137 | def compute_v(self): 138 | for vert in self.mesh.verts: 139 | vert.v = (vert.x - vert.x_n) / self.dt 140 | 141 | @ti.kernel 142 | def update_x(self,alpha:float): 143 | for vert in self.mesh.verts: 144 | vert.x = vert.x_prev + alpha * vert.delta_x 145 | 146 | @ti.kernel 147 | def update_and_bound(self): 148 | for vert in self.mesh.verts: 149 | vert.v = (vert.x - vert.x_n) / self.dt 150 | if vert.x[1] < self.ground: 151 | vert.x[1] = self.ground 152 | if vert.v[1] < 0.0: 153 | vert.v[1] = 0.0 154 | 155 | @ti.kernel 156 | def assign_b(self): 157 | for vert in self.mesh.verts: 158 | vert.b = - vert.grad 159 | 160 | @ti.kernel 161 | def assign_r(self): 162 | # r = b - Ax 163 | for vert in self.mesh.verts: 164 | vert.r = vert.b - vert.mul_ans 165 | 166 | @ti.kernel 167 | def assign_d(self): 168 | for vert in self.mesh.verts: 169 | vert.d = vert.r / vert.diagH 170 | 171 | @ti.kernel 172 | def compute_r_dot_d(self)->float: 173 | ret = 0.0 174 | for vert in self.mesh.verts: 175 | ret += vert.r.dot(vert.d) 176 | return ret 177 | 178 | @ti.kernel 179 | def compute_q_dot_d(self)->float: 180 | ret = 0.0 181 | for vert in self.mesh.verts: 182 | vert.q = vert.mul_ans 183 | ret += vert.q.dot(vert.d) 184 | return ret 185 | 186 | @ti.kernel 187 | def assign_tmp_as_delta_x(self): 188 | for vert in self.mesh.verts: 189 | vert.tmp = vert.delta_x 190 | 191 | @ti.kernel 192 | def assign_tmp_as_d(self): 193 | for vert in self.mesh.verts: 194 | vert.tmp = vert.d 195 | 196 | @ti.kernel 197 | def update_delta_x(self,alpha:float): 198 | for vert in self.mesh.verts: 199 | vert.delta_x += alpha * vert.d 200 | 201 | @ti.kernel 202 | def update_r(self,alpha:float): 203 | for vert in self.mesh.verts: 204 | vert.r -= alpha * vert.q 205 | 206 | @ti.kernel 207 | def assign_tmp_as_s(self): 208 | for vert in self.mesh.verts: 209 | vert.tmp = vert.r / vert.diagH 210 | 211 | @ti.kernel 212 | def compute_r_dot_s(self)->float: 213 | ret = 0.0 214 | for vert in self.mesh.verts: 215 | ret += vert.r.dot(vert.tmp) 216 | return ret 217 | 218 | @ti.kernel 219 | def update_d(self,beta:float): 220 | for vert in self.mesh.verts: 221 | vert.d = vert.tmp + beta * vert.d 222 | 223 | 224 | def pcg_newton_solver(self): 225 | epsilon = 1e-6 226 | iter_max = 1000 227 | self.compute_grad_and_diagH() 228 | self.assign_b() # b = - grad 229 | self.assign_tmp_as_delta_x() 230 | self.mul_operation() # Ax , x in pcg is the delta_x in the newton method 231 | self.assign_r() # r = b - Ax 232 | self.assign_d() # d = M_inv r 233 | sig_new = self.compute_r_dot_d() 234 | sig_0 = sig_new 235 | for i in range(iter_max): 236 | self.assign_tmp_as_d() 237 | self.mul_operation() # q = A @ d 238 | q_d = self.compute_q_dot_d() 239 | alpha = sig_new / q_d 240 | self.update_delta_x(alpha) # x = x + alpha d 241 | 242 | # if i % 50 == 0 and i > 1: 243 | # # restart 244 | # self.assign_tmp_as_delta_x() 245 | # self.mul_operation() # Ax 246 | # self.assign_r() # r = b - Ax 247 | # else: 248 | self.update_r(alpha) # r = r - alpha q 249 | 250 | self.assign_tmp_as_s() # s = M_inv r 251 | sig_old = sig_new 252 | sig_new = self.compute_r_dot_s() 253 | beta = sig_new / sig_old 254 | self.update_d(beta) 255 | 256 | if sig_new < epsilon**2 * sig_0: 257 | break 258 | print('pcg finish at iter', i, 'rate', sig_new / sig_0, 'converage', i<(iter_max-1)) 259 | return i 260 | 261 | def step(self): 262 | self.frame += 1 263 | self.assign_xn_xhat() 264 | self.iter_max = 50 265 | for iter in range(self.iter_max): 266 | self.pcg_newton_solver() # delta_x 267 | delta_x_norm = self.compute_delta_x_inf_norm() 268 | E0 = self.compute_E() 269 | self.mesh.verts.x_prev.copy_from(self.mesh.verts.x) 270 | alpha = 1.0 271 | self.update_x(alpha) 272 | E = self.compute_E() 273 | while E > E0 + 1e-7: 274 | alpha = alpha * 0.5 275 | self.update_x(alpha) 276 | E = self.compute_E() 277 | print("iter " , iter, "[Step size", alpha, 'delta_x_norm', delta_x_norm, "]") 278 | if alpha * delta_x_norm < 1e-2 * self.dt: 279 | print('iter finish with iter', iter, delta_x_norm) 280 | break 281 | self.update_and_bound() 282 | 283 | 284 | 285 | if __name__ == '__main__': 286 | ti.init(arch=ti.gpu, default_fp=ti.f32)#, device_memory_fraction=0.9)#,kernel_profiler=True),advanced_optimization=True,fast_math=True) 287 | demos = ['armadillo_drop_collision_free','Patrick_Star','cube','cube_10','cube_20','cube_40','banana'] 288 | demo = demos[-1] 289 | 290 | deformer = newton_base_deformer(demo = demo) 291 | print('init finish') 292 | deformer.visual() -------------------------------------------------------------------------------- /algorithm/newton_sparse_solver.py: -------------------------------------------------------------------------------- 1 | # Taichi 官方的matrix solver的实现 2 | import numpy as np 3 | np.set_printoptions(suppress=True) 4 | from algorithm.pncg_base_collision_free import * 5 | from util.model_loading import * 6 | 7 | 8 | # from math_utils.cubic_roots import * 9 | 10 | 11 | @ti.data_oriented 12 | class newton_base_deformer(base_deformer): 13 | def __init__(self, demo): 14 | model = model_loading(demo=demo) 15 | self.demo = demo 16 | print('demo', self.demo) 17 | self.dict = model.dict 18 | self.mu, self.la = model.mu, model.la 19 | print('mu', self.mu, 'la', self.la) 20 | self.density = model.density 21 | self.dt = model.dt 22 | self.gravity = model.gravity 23 | self.ground = model.ground 24 | print('ground', self.ground) 25 | self.mesh = model.mesh 26 | self.ground = model.ground 27 | self.frame = 0 28 | self.epsilon = model.epsilon 29 | self.iter_max = model.iter_max 30 | self.camera_position = model.camera_position 31 | self.camera_lookat = model.camera_lookat 32 | self.SMALL_NUM = 1e-7 33 | # initialize model 34 | self.mesh.verts.place({'x': ti.types.vector(3, float), 35 | 'v': ti.types.vector(3, float), 36 | 'm': float, 37 | 'x_n': ti.types.vector(3, float), 38 | 'x_hat': ti.types.vector(3, float), 39 | 'x_prev': ti.types.vector(3, float), 40 | 'x_init': ti.types.vector(3, float), 41 | 'grad': ti.types.vector(3, float), 42 | }) 43 | 44 | self.mesh.cells.place({'B': ti.math.mat3, 'W': float}) 45 | self.mesh.verts.x.from_numpy(self.mesh.get_position_as_numpy()) 46 | self.mesh.verts.x_init.copy_from(self.mesh.verts.x) 47 | self.n_verts = self.mesh._vert_position.shape[0] 48 | self.n_cells = len(self.mesh.cells) 49 | print('n_verts,n_cells', self.n_verts, self.n_cells) 50 | 51 | # precompute 52 | self.precompute() 53 | self.indices = ti.field(ti.i32, shape=len(self.mesh.cells) * 4 * 3) 54 | self.init_indices() 55 | self.assign_elastic_type(model.elastic_type) 56 | self.set_point_lights() 57 | self.config = model.dict 58 | self.b = ti.ndarray(float, 3 * self.n_verts) 59 | self.MatrixBuilder = ti.linalg.SparseMatrixBuilder(3 * self.n_verts, 3 * self.n_verts, max_num_triplets=10000000) 60 | elastic = model.elastic_type 61 | if elastic == 'ARAP': 62 | self.compute_d2PsidF2 = compute_d2PsidF2_ARAP 63 | elif elastic == 'ARAP_filter': 64 | self.compute_d2PsidF2 = compute_d2PsidF2_ARAP_filter 65 | elif elastic == 'SNH': 66 | self.compute_d2PsidF2 = compute_d2PsidF2_SNH 67 | elif elastic == 'FCR': 68 | self.compute_d2PsidF2 = compute_d2PsidF2_FCR 69 | elif elastic == 'FCR_filter': 70 | self.compute_d2PsidF2 = compute_d2PsidF2_FCR_filter 71 | elif elastic == 'NH': 72 | self.compute_d2PsidF2 = compute_d2PsidF2_NH 73 | 74 | 75 | @ti.kernel 76 | def assign_xn_xhat(self): 77 | ti.mesh_local(self.mesh.verts.x) 78 | for vert in self.mesh.verts: 79 | vert.x_n = vert.x 80 | vert.x_hat = vert.x + self.dt * vert.v 81 | vert.x_hat[1] += self.dt * self.dt * self.gravity 82 | 83 | @ti.kernel 84 | def compute_E(self) -> float: 85 | E = 0.0 86 | ti.mesh_local(self.mesh.verts.x) 87 | for vert in self.mesh.verts: 88 | E += 0.5 * vert.m * (vert.x - vert.x_hat).norm_sqr() 89 | for c in self.mesh.cells: 90 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 91 | F = Ds @ c.B 92 | Psi = self.compute_Psi(F, self.mu, self.la) 93 | E += (self.dt ** 2) * c.W * Psi 94 | return E 95 | 96 | @ti.kernel 97 | def assemble_Elastic(self, A: ti.types.sparse_matrix_builder()): 98 | # ti.mesh_local(self.mesh.verts.x) 99 | for vert in self.mesh.verts: 100 | id = vert.id 101 | mass = vert.m 102 | A[3 * id, 3 * id] += mass 103 | A[3 * id + 1, 3 * id + 1] += mass 104 | A[3 * id + 2, 3 * id + 2] += mass 105 | vert.grad = vert.m * (vert.x - vert.x_hat) 106 | for c in self.mesh.cells: 107 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 108 | B = c.B 109 | F = Ds @ B 110 | dFdx = compute_dFdx(B) # 9x12 111 | para = self.dt ** 2 * c.W 112 | dPsidx = para * self.compute_dPsidx(F, B, self.mu, self.la) 113 | d2PsidF2 = self.compute_d2PsidF2(F, self.mu, self.la) 114 | d2Psidx2 = (dFdx.transpose()) @ d2PsidF2 @ dFdx # 12x12 115 | # d2Psidx2 = spd_matrix(d2Psidx2) 116 | for i in range(4): 117 | c.verts[i].grad += ti.Vector([dPsidx[3 * i], dPsidx[3 * i + 1], dPsidx[3 * i + 2]], float) 118 | 119 | A_tmp = para * d2Psidx2 120 | ids = ti.Vector([c.verts[0].id, c.verts[1].id, c.verts[2].id, c.verts[3].id], ti.i32) 121 | for o,p,m,n in ti.ndrange(3,3,4,4): 122 | A[3 * ids[m] + o, 3 * ids[n] + p] += A_tmp[3 * m + o, 3 * n + p] 123 | 124 | @ti.kernel 125 | def assemble_A(self, A: ti.types.sparse_matrix_builder()): 126 | # ti.mesh_local(self.mesh.verts.x) 127 | for vert in self.mesh.verts: 128 | id = vert.id 129 | mass = vert.m 130 | A[3 * id, 3 * id] += mass 131 | A[3 * id + 1, 3 * id + 1] += mass 132 | A[3 * id + 2, 3 * id + 2] += mass 133 | for c in self.mesh.cells: 134 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 135 | B = c.B 136 | F = Ds @ B 137 | dFdx = compute_dFdx(B) # 9x12 138 | para = self.dt ** 2 * c.W 139 | d2PsidF2 = self.compute_d2PsidF2(F, self.mu, self.la) 140 | d2Psidx2 = (dFdx.transpose()) @ d2PsidF2 @ dFdx # 12x12 141 | # d2Psidx2 = spd_matrix(d2Psidx2) 142 | A_tmp = para * d2Psidx2 143 | ids = ti.Vector([c.verts[0].id, c.verts[1].id, c.verts[2].id, c.verts[3].id], ti.i32) 144 | for m in ti.static(range(4)): # m 行 145 | for n in ti.static(range(4)): # n 列 146 | for o in ti.static(range(3)): 147 | for p in ti.static(range(3)): 148 | # A[3 * c.verts[m].id + o, 3 * c.verts[n].id + p] += A_tmp[3 * m + o, 3 * n + p] 149 | A[3 * ids[m] + o, 3 * ids[n] + p] += A_tmp[3 * m + o, 3 * n + p] 150 | # for o,p,m,n in ti.ndrange(3,3,4,4): 151 | # A[3 * ids[m] + o, 3 * ids[n] + p] += A_tmp[3 * m + o, 3 * n + p] 152 | 153 | @ti.kernel 154 | def compute_grad(self): 155 | # b = - grad 156 | for vert in self.mesh.verts: 157 | vert.grad = vert.m * (vert.x - vert.x_hat) 158 | # ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.x, self.mesh.verts.diagH) 159 | for c in self.mesh.cells: 160 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 161 | B = c.B 162 | F = Ds @ B # 3x3 163 | para = c.W * self.dt ** 2 164 | dPsidx = para * self.compute_dPsidx(F, B, self.mu, self.la) 165 | for i in range(4): 166 | c.verts[i].grad += ti.Vector([dPsidx[3 * i], dPsidx[3 * i +1], dPsidx[3 * i + 2]], float) 167 | 168 | @ti.kernel 169 | def compute_delta_x_inf_norm(self, delta_x:ti.types.ndarray() ) -> float: 170 | ret = 0.0 171 | for i in delta_x: 172 | ti.atomic_max(ret, ti.abs(delta_x[i])) 173 | return ret 174 | 175 | @ti.kernel 176 | def compute_v(self): 177 | for vert in self.mesh.verts: 178 | vert.v = (vert.x - vert.x_n) / self.dt 179 | 180 | 181 | @ti.kernel 182 | def update_2(self, delta_x_: ti.types.ndarray()): 183 | for vert in self.mesh.verts: 184 | id = vert.id 185 | delta_x = ti.Vector([delta_x_[3 * id], delta_x_[3 * id + 1], delta_x_[3 * id + 2]], ti.f32) 186 | vert.x += delta_x 187 | vert.v = delta_x / self.dt 188 | if vert.x[1] < 0.0: 189 | vert.x[1] = 0.0 190 | if vert.v[1] < 0.0: 191 | vert.v[1] = 0.0 192 | 193 | @ti.kernel 194 | def update_x(self, alpha: float, delta_x_: ti.types.ndarray()): 195 | for vert in self.mesh.verts: 196 | id = vert.id 197 | delta_x = ti.Vector([delta_x_[3 * id], delta_x_[3 * id + 1], delta_x_[3 * id + 2]], ti.f32) 198 | vert.x = vert.x_prev + alpha * delta_x 199 | @ti.kernel 200 | def assign_b(self, b_: ti.types.ndarray()): 201 | for vert in self.mesh.verts: 202 | id = vert.id 203 | b_[3 * id] = -vert.grad[0] 204 | b_[3 * id + 1] = -vert.grad[1] 205 | b_[3 * id + 2] = -vert.grad[2] 206 | 207 | @ti.kernel 208 | def copy_to_mesh(self, des: ti.types.ndarray(), source: ti.template()): 209 | for i in range(self.n_verts): 210 | source[i][0] = des[3 * i] 211 | source[i][1] = des[3 * i + 1] 212 | source[i][2] = des[3 * i + 2] 213 | 214 | @ti.kernel 215 | def update_v_and_bound(self): 216 | for vert in self.mesh.verts: 217 | vert.v = (vert.x - vert.x_n) / self.dt 218 | if vert.x[1] < self.ground: 219 | vert.x[1] = self.ground 220 | if vert.v[1] < 0.0: 221 | vert.v[1] = 0.0 222 | 223 | def step(self): 224 | self.frame += 1 225 | self.assign_xn_xhat() 226 | self.iter_max = 50 227 | for iter in range(self.iter_max): 228 | # self.compute_grad() 229 | self.assemble_Elastic(self.MatrixBuilder) 230 | A = self.MatrixBuilder.build() 231 | self.assign_b(self.b) # b = - grad 232 | solver = ti.linalg.SparseSolver(solver_type="LDLT") 233 | solver.analyze_pattern(A) 234 | solver.factorize(A) 235 | delta_x = solver.solve(self.b) 236 | delta_x_norm = self.compute_delta_x_inf_norm(delta_x) 237 | E0 = self.compute_E() 238 | self.mesh.verts.x_prev.copy_from(self.mesh.verts.x) 239 | alpha = 1.0 240 | self.update_x(alpha, delta_x) 241 | E = self.compute_E() 242 | while E > E0: 243 | alpha = alpha * 0.5 244 | self.update_x(alpha, delta_x) 245 | E = self.compute_E() 246 | print("iter " , iter, "[Step size after line search: ", alpha, 'delta_x_norm', delta_x_norm, "]") 247 | print(delta_x[0]) 248 | if delta_x_norm < 1e-2 * self.dt: 249 | print('iter finish with iter', iter, delta_x_norm) 250 | break 251 | self.update_v_and_bound() 252 | 253 | def step2(self): 254 | self.frame += 1 255 | self.assign_xn_xhat() 256 | self.compute_grad() 257 | self.assemble_A(self.MatrixBuilder) 258 | # self.assemble_Elastic(self.MatrixBuilder) 259 | A = self.MatrixBuilder.build() 260 | self.assign_b(self.b) # b = - grad 261 | solver = ti.linalg.SparseSolver(solver_type="LDLT") 262 | solver.analyze_pattern(A) 263 | solver.factorize(A) 264 | delta_x = solver.solve(self.b) 265 | # self.copy_to_mesh(delta_x, self.mesh.verts.delta_x) 266 | self.update_2(delta_x) 267 | 268 | def step_sparse_iterative_solver(self): 269 | self.frame += 1 270 | self.assign_xn_xhat() 271 | self.iter_max = 10 272 | for iter in range(self.iter_max): 273 | self.assemble_Elastic(self.MatrixBuilder) 274 | # print('matrix assemble finish') 275 | A = self.MatrixBuilder.build() 276 | self.assign_b(self.b, self.mesh.verts.grad) # b = - grad 277 | 278 | # sparse iterative solver 279 | solver = ti.linalg.SparseCG(A=A,b=self.b) 280 | delta_x, exit_code = solver.solve() 281 | print(exit_code) 282 | 283 | self.copy_to_mesh(delta_x, self.mesh.verts.delta_x) 284 | delta_x_norm = self.compute_delta_x_inf_norm() 285 | E0 = self.compute_E() 286 | self.mesh.verts.x_prev.copy_from(self.mesh.verts.x) 287 | alpha = 1.0 288 | self.update_x(alpha) 289 | E = self.compute_E() 290 | while E > E0: 291 | alpha = alpha * 0.5 292 | self.update_x(alpha) 293 | E = self.compute_E() 294 | print("iter ", iter, "[Step size after line search: ", alpha, "]") 295 | if delta_x_norm < 1e-3 * (self.dt ** 2): 296 | print('iter finish with iter', iter, delta_x_norm) 297 | break 298 | self.update_v_and_bound() 299 | 300 | 301 | if __name__ == '__main__': 302 | ti.init(arch=ti.cpu, default_fp=ti.f32) # it does not work on GPU ? 303 | demos = ['cube','cube_10','banana'] 304 | demo = demos[2] 305 | 306 | deformer = newton_base_deformer(demo = demo) 307 | print('init finish') 308 | # for i in range(10): 309 | # deformer.step() 310 | deformer.visual() -------------------------------------------------------------------------------- /algorithm/pncg_base_collision_free.py: -------------------------------------------------------------------------------- 1 | from algorithm.base_deformer import * 2 | from util.model_loading import * 3 | 4 | @ti.data_oriented 5 | class pncg_base_deformer(base_deformer): 6 | def __init__(self, demo): 7 | model = model_loading(demo=demo) 8 | self.demo = demo 9 | print('demo', self.demo) 10 | self.dict = model.dict 11 | self.mu, self.la = model.mu, model.la 12 | print('mu', self.mu, 'la', self.la) 13 | self.density = model.density 14 | self.dt = model.dt 15 | self.gravity = model.gravity 16 | self.ground = model.ground 17 | print('ground', self.ground) 18 | self.mesh = model.mesh 19 | self.ground = model.ground 20 | self.frame = 0 21 | self.epsilon = model.epsilon 22 | self.iter_max = model.iter_max 23 | self.camera_position = model.camera_position 24 | self.camera_lookat = model.camera_lookat 25 | self.SMALL_NUM = 1e-7 26 | # initialize model 27 | self.mesh.verts.place({'x': ti.types.vector(3, float), 28 | 'v': ti.types.vector(3, float), 29 | 'm': float, 30 | 'x_n': ti.types.vector(3, float), 31 | 'x_hat': ti.types.vector(3, float), 32 | 'x_prev': ti.types.vector(3, float), 33 | 'x_init': ti.types.vector(3, float), 34 | 'grad': ti.types.vector(3, float), 35 | 'grad_prev': ti.types.vector(3, float), 36 | 'p': ti.types.vector(3, float), 37 | }) 38 | self.mesh.verts.place({'diagH': ti.types.vector(3, float)}) 39 | self.mesh.cells.place({'B': ti.math.mat3, 'W': float}) 40 | self.mesh.verts.x.from_numpy(self.mesh.get_position_as_numpy()) 41 | self.mesh.verts.x_init.copy_from(self.mesh.verts.x) 42 | self.n_verts = self.mesh._vert_position.shape[0] 43 | self.n_cells = len(self.mesh.cells) 44 | print('n_verts,n_cells', self.n_verts, self.n_cells) 45 | 46 | # precompute 47 | self.precompute() 48 | self.indices = ti.field(ti.i32, shape=len(self.mesh.cells) * 4 * 3) 49 | self.init_indices() 50 | self.assign_elastic_type(model.elastic_type) 51 | self.set_point_lights() 52 | self.config = model.dict 53 | 54 | @ti.kernel 55 | def compute_E(self) -> float: 56 | """Compute energy""" 57 | E = 0.0 58 | for vert in self.mesh.verts: 59 | E += 0.5 * vert.m * (vert.x - vert.x_hat).norm_sqr() 60 | for c in self.mesh.cells: 61 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 62 | F = Ds @ c.B 63 | Psi = self.compute_Psi(F, self.mu, self.la) 64 | E += (self.dt ** 2) * c.W * Psi 65 | return E 66 | 67 | @ti.kernel 68 | def compute_grad_and_diagH(self): 69 | for vert in self.mesh.verts: 70 | vert.grad_prev = vert.grad 71 | vert.grad = vert.m * (vert.x - vert.x_hat) 72 | vert.diagH = vert.m * ti.Vector.one(float, 3) 73 | for c in self.mesh.cells: 74 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 75 | B = c.B 76 | F = Ds @ B # 3x3 77 | para = c.W * self.dt ** 2 78 | dPsidx = para * self.compute_dPsidx(F, B, self.mu, self.la) 79 | diagH_d2Psidx2 = para * self.compute_diag_d2Psidx2(F, B, self.mu, self.la) 80 | for i in range(4): 81 | c.verts[i].grad += ti.Vector([dPsidx[3 * i], dPsidx[3 * i + 1], dPsidx[3 * i + 2]], float) 82 | tmp = ti.Vector([diagH_d2Psidx2[3 * i], diagH_d2Psidx2[3 * i + 1], diagH_d2Psidx2[3 * i + 2]]) 83 | tmp = ti.max(tmp, 0.0) 84 | c.verts[i].diagH += tmp 85 | 86 | @ti.kernel 87 | def compute_pHp(self) -> float: 88 | ret = 0.0 89 | for vert in self.mesh.verts: 90 | ret += vert.p.norm_sqr() * vert.m 91 | 92 | for c in self.mesh.cells: 93 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 94 | B = c.B 95 | F = Ds @ B 96 | p = ti.Vector.zero(float, 12) 97 | p[0:3] = c.verts[0].p 98 | p[3:6] = c.verts[1].p 99 | p[6:9] = c.verts[2].p 100 | p[9:12] = c.verts[3].p 101 | tmp = self.compute_p_d2Psidx2_p(F, B, p, self.mu, self.la) 102 | ret += c.W * self.dt ** 2 * ti.max(tmp, 0.0) # clamp negetive value to 0, similar to spd projection 103 | return ret 104 | 105 | @ti.kernel 106 | def assign_xn_xhat(self): 107 | ti.mesh_local(self.mesh.verts.x) # somewhere mesh_local would raise error, why? 108 | for vert in self.mesh.verts: 109 | vert.x_n = vert.x 110 | vert.x_hat = vert.x + self.dt * vert.v 111 | vert.x_hat[1] += self.dt * self.dt * self.gravity 112 | 113 | @ti.kernel 114 | def compute_grad_inf_norm(self) -> float: 115 | ret = 0.0 116 | for vert in self.mesh.verts: 117 | ti.atomic_max(ret, (ti.abs(vert.grad)).max()) 118 | return ret 119 | 120 | @ti.kernel 121 | def update_v(self): 122 | for vert in self.mesh.verts: 123 | vert.v = (vert.x - vert.x_n) / self.dt 124 | 125 | @ti.kernel 126 | def update_x(self, alpha: float): 127 | for vert in self.mesh.verts: 128 | vert.x += alpha * vert.p 129 | 130 | @ti.kernel 131 | def update_v_and_bound(self): 132 | """if object hits ground, set x to be ground and v to be 0. It would cause nan for NH material""" 133 | for vert in self.mesh.verts: 134 | vert.v = (vert.x - vert.x_n) / self.dt 135 | if vert.x[1] < self.ground: 136 | vert.x[1] = self.ground 137 | if vert.v[1] < 0.0: 138 | vert.v[1] = 0.0 139 | 140 | @ti.kernel 141 | def compute_init_p(self): 142 | for vert in self.mesh.verts: 143 | vert.p = - vert.grad / vert.diagH 144 | 145 | @ti.kernel 146 | def compute_gTp(self) -> float: 147 | gTp = 0.0 148 | for vert in self.mesh.verts: 149 | gTp += vert.grad.dot(vert.p) 150 | return gTp 151 | 152 | @ti.kernel 153 | def compute_DK_direction(self): 154 | g_p = 0.0 # g^{\top} p 155 | g_Py = 0.0 156 | y_p = 0.0 157 | y_Py = 0.0 158 | ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.diagH, self.mesh.verts.p) 159 | for vert in self.mesh.verts: 160 | y = vert.grad - vert.grad_prev 161 | Py = y / vert.diagH 162 | y_p += y.dot(vert.p) 163 | g_Py += vert.grad.dot(Py) 164 | y_Py += y.dot(Py) 165 | g_p += vert.grad.dot(vert.p) 166 | beta = (g_Py - y_Py * g_p / y_p) / y_p 167 | for vert in self.mesh.verts: 168 | vert.p = - vert.grad / vert.diagH + beta * vert.p 169 | 170 | @ti.kernel 171 | def compute_FR_direction(self): 172 | g_P_g = 0.0 173 | gk_P_gk = 0.0 174 | ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.diagH, self.mesh.verts.p) 175 | for vert in self.mesh.verts: 176 | g_P_g += vert.grad.dot(vert.grad / vert.diagH) 177 | gk_P_gk += vert.grad_prev.dot(vert.grad_prev / vert.diagH) 178 | beta = g_P_g / gk_P_gk 179 | for vert in self.mesh.verts: 180 | vert.p = - vert.grad / vert.diagH + beta * vert.p 181 | 182 | @ti.kernel 183 | def compute_CD_direction(self): 184 | g_k_p = 0.0 185 | gkp1_P_gkp1 = 0.0 186 | ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.diagH, self.mesh.verts.p) 187 | for vert in self.mesh.verts: 188 | g_k_p += vert.grad_prev.dot(vert.p) 189 | gkp1_P_gkp1 += vert.grad.dot(vert.grad / vert.diagH) 190 | beta = - gkp1_P_gkp1 / g_k_p 191 | for vert in self.mesh.verts: 192 | vert.p = - vert.grad / vert.diagH + beta * vert.p 193 | 194 | @ti.kernel 195 | def compute_PR_direction(self): 196 | g_k_p = 0.0 197 | gkp1_P_y = 0.0 198 | ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.diagH, self.mesh.verts.p) 199 | for vert in self.mesh.verts: 200 | g_k_p += vert.grad_prev.dot(vert.p) 201 | y = vert.grad - vert.grad_prev 202 | gkp1_P_y += vert.grad.dot(y) 203 | beta = - gkp1_P_y / g_k_p 204 | for vert in self.mesh.verts: 205 | vert.p = - vert.grad / vert.diagH + beta * vert.p 206 | 207 | @ti.kernel 208 | def compute_DK_plus_direction(self): 209 | g_Py = 0.0 210 | y_p = 0.0 211 | y_Py = 0.0 212 | g_p = 0.0 213 | p_norm = 0.0 214 | ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.diagH, self.mesh.verts.p, self.mesh.verts.grad_prev) 215 | for vert in self.mesh.verts: 216 | diagH = vert.diagH 217 | grad = vert.grad 218 | y = grad - vert.grad_prev 219 | Py = y / diagH 220 | y_p += y.dot(vert.p) 221 | g_Py += grad.dot(Py) 222 | y_Py += y.dot(Py) 223 | g_p += grad.dot(vert.p) 224 | p_norm += vert.p.norm_sqr() 225 | beta = (g_Py - y_Py * g_p / y_p) / y_p 226 | # print('beta', beta) 227 | beta_plus = ti.max(beta, 0.01 * g_p / p_norm) 228 | # beta_plus = ti.max(beta, 0.0) 229 | if beta_plus > beta: 230 | print('beta', beta) 231 | print('beta_plus', beta_plus) 232 | for vert in self.mesh.verts: 233 | vert.p = - vert.grad / vert.diagH + beta_plus * vert.p 234 | 235 | @ti.kernel 236 | def compute_BFGS_direction(self, alpha: float): 237 | g_Py = 0.0 238 | y_p = 0.0 239 | y_Py = 0.0 240 | g_p = 0.0 241 | ti.mesh_local(self.mesh.verts.grad, self.mesh.verts.diagH, self.mesh.verts.p, self.mesh.verts.grad_prev) 242 | for vert in self.mesh.verts: 243 | diagH = vert.diagH 244 | grad = vert.grad 245 | y = grad - vert.grad_prev 246 | Py = y / diagH 247 | y_p += y.dot(vert.p) 248 | g_Py += grad.dot(Py) 249 | y_Py += y.dot(Py) 250 | g_p += grad.dot(vert.p) 251 | beta = ( g_Py - (alpha + y_Py / y_p) * g_p ) / y_p 252 | gamma = g_p / y_p 253 | for vert in self.mesh.verts: 254 | Py = (vert.grad - vert.grad_prev) / vert.diagH 255 | vert.p = - vert.grad / vert.diagH + beta * vert.p + gamma * Py 256 | 257 | @ti.kernel 258 | def compute_newton_alpha(self) -> (float,float,float): 259 | """ Compute step size and update x 260 | pHp: p^{\top} H p; gTp: grad^{top} p""" 261 | pHp = 0.0 262 | gTp = 0.0 263 | for vert in self.mesh.verts: 264 | gTp += vert.grad.dot(vert.p) 265 | pHp += vert.p.norm_sqr() * vert.m 266 | 267 | for c in self.mesh.cells: 268 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 269 | B = c.B 270 | F = Ds @ B 271 | p = ti.Vector.zero(float, 12) 272 | p[0:3] = c.verts[0].p 273 | p[3:6] = c.verts[1].p 274 | p[6:9] = c.verts[2].p 275 | p[9:12] = c.verts[3].p 276 | tmp = self.compute_p_d2Psidx2_p(F, B, p, self.mu, self.la) 277 | pHp += c.W * self.dt ** 2 * ti.max(tmp, 0.0) 278 | alpha = - gTp / pHp 279 | for vert in self.mesh.verts: 280 | vert.x += alpha * vert.p 281 | return (alpha, gTp, pHp) 282 | 283 | @ti.kernel 284 | def dirichlet_grad(self): 285 | # set the gradient of dirichelet vertice to be 0 286 | for vert in self.mesh.verts: #S(grad) 287 | if vert.is_dirichlet == 1: 288 | vert.grad = ti.Vector([0, 0, 0]) 289 | 290 | def init_dirichlet(self): 291 | print('init dirichlet') 292 | self.mesh.verts.place({'is_dirichlet': ti.i32}) 293 | path = self.dict['model_paths'][0].rsplit('/',1)[0] + '/is_dirichlet.npy' 294 | dirichlet_np = np.load(path) 295 | print('load np') 296 | print(dirichlet_np.shape, self.n_verts) 297 | self.mesh.verts.is_dirichlet.from_numpy(dirichlet_np) 298 | print('dirichlet init finish') 299 | 300 | def step(self): 301 | print('Frame', self.frame) 302 | self.assign_xn_xhat() 303 | self.compute_grad_and_diagH() 304 | self.compute_init_p() 305 | alpha, gTp, pHp = self.compute_newton_alpha() 306 | delta_E = - alpha * gTp - 0.5 * alpha**2 * pHp 307 | delta_E_init = delta_E 308 | for iter in range(self.iter_max): 309 | if delta_E < self.epsilon * delta_E_init: 310 | break 311 | else: 312 | print('iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 'pHp', 313 | pHp) 314 | self.compute_grad_and_diagH() 315 | self.compute_DK_direction() 316 | alpha, gTp, pHp = self.compute_newton_alpha() 317 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 318 | print('finish at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', 319 | gTp, 'pHp', pHp) 320 | self.update_v_and_bound() 321 | self.frame += 1 322 | return iter -------------------------------------------------------------------------------- /algorithm/pncg_base_ipc.py: -------------------------------------------------------------------------------- 1 | from algorithm.collision_detection_v2 import * 2 | from util.model_loading import * 3 | 4 | @ti.data_oriented 5 | class pncg_ipc_deformer(collision_detection_module_v2): 6 | def __init__(self, demo = 'cube_0'): 7 | model = model_loading(demo=demo) 8 | self.demo = demo 9 | print('demo', self.demo) 10 | self.dict = model.dict 11 | self.mu, self.la = model.mu, model.la 12 | self.density = model.density 13 | self.dt = model.dt 14 | self.gravity = model.gravity 15 | self.ground = model.ground 16 | self.mesh = model.mesh 17 | self.epsilon = model.epsilon 18 | self.iter_max = model.iter_max 19 | self.camera_position = model.camera_position 20 | self.camera_lookat = model.camera_lookat 21 | self.adj = model.adj 22 | self.ground_barrier = model.ground_barrier 23 | self.frame = 0 24 | self.SMALL_NUM = 1e-7 25 | 26 | # initialize model 27 | self.mesh.verts.place({'x': ti.types.vector(3,float), 28 | 'v': ti.types.vector(3,float), 29 | 'm': float, 30 | 'x_n': ti.types.vector(3,float), 31 | 'x_hat': ti.types.vector(3,float), 32 | 'x_prev': ti.types.vector(3,float), 33 | 'x_init': ti.types.vector(3, float), 34 | 'grad': ti.types.vector(3,float), 35 | 'grad_prev': ti.types.vector(3,float), 36 | 'p': ti.types.vector(3,float), 37 | 'diagH': ti.types.vector(3, float), 38 | # 'is_contact': int, 39 | # 'is_dirichlet': int, 40 | }) 41 | 42 | self.mesh.cells.place({'B': ti.math.mat3, 'W': float}) 43 | self.mesh.verts.x.from_numpy(self.mesh.get_position_as_numpy()) 44 | self.mesh.verts.x_init.copy_from(self.mesh.verts.x) 45 | self.mesh.verts.x_prev.copy_from(self.mesh.verts.x) 46 | self.n_verts = len(self.mesh.verts) 47 | self.n_cells = len(self.mesh.cells) 48 | print('n_verts,n_cells',self.n_verts,self.n_cells) 49 | 50 | #precompute 51 | print('precompute!!') 52 | self.precompute() 53 | self.indices = ti.field(ti.i32, shape=len(self.mesh.cells) * 4 * 3) 54 | self.init_indices() 55 | self.assign_elastic_type(model.elastic_type) 56 | 57 | # Because MeshTaichi doesn't support parallel boundary edges and elements at the same time 58 | self.boundary_points = model.boundary_points 59 | self.boundary_edges = model.boundary_edges 60 | self.boundary_triangles = model.boundary_triangles 61 | self.n_boundary_points = self.boundary_points.shape[0] 62 | self.n_boundary_edges = self.boundary_edges.shape[0] 63 | self.n_boundary_triangles = self.boundary_triangles.shape[0] 64 | print('boundary size ', self.n_boundary_points, self.n_boundary_edges, self.n_boundary_triangles) 65 | self.set_point_lights() 66 | print('init grids') 67 | self.kappa = model.kappa 68 | self.dHat = model.dHat 69 | self.init_hash_grid() 70 | print('dHat:', self.dHat, 'kappa ', self.kappa) 71 | 72 | self.config = model.dict 73 | self.config['dHat'] = self.dHat 74 | self.config['kappa'] = self.kappa 75 | 76 | @ti.func 77 | def barrier_E(self, d): 78 | E = -self.kappa * (d - self.dHat) ** 2 * ti.log(d / self.dHat) 79 | return E 80 | 81 | @ti.func 82 | def barrier_g(self, d): 83 | t2 = d - self.dHat 84 | g = self.kappa * (t2 * ti.log(d / self.dHat) * (-2.0) - (t2 ** 2) / d) 85 | return g 86 | 87 | @ti.func 88 | def barrier_H(self, d): 89 | dHat = self.dHat 90 | H = self.kappa * ((-2) * ti.log(d / dHat) - 4 + 4 * dHat / d + (d - dHat) ** 2 / d ** 2) 91 | return H 92 | 93 | @ti.kernel 94 | def update_x_v2(self,alpha:float): 95 | for vert in self.mesh.verts: 96 | vert.x = vert.x_prev + alpha * vert.p 97 | 98 | @ti.kernel 99 | def compute_E(self) -> float: 100 | E = 0.0 101 | for vert in self.mesh.verts: 102 | E += 0.5 * vert.m * (vert.x - vert.x_hat).norm_sqr() 103 | for c in self.mesh.cells: 104 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 105 | F = Ds @ c.B 106 | Psi = self.compute_Psi(F, self.mu, self.la) 107 | E += (self.dt ** 2) * c.W * Psi 108 | for k,j in self.cid: 109 | pair = self.cid[k,j] 110 | dist = pair.b 111 | E_ipc = self.barrier_E(dist) 112 | E += E_ipc 113 | return E 114 | 115 | @ti.kernel 116 | def compute_grad_and_diagH(self): 117 | # inertia potential 118 | ti.mesh_local(self.mesh.verts.grad) 119 | for vert in self.mesh.verts: 120 | m = vert.m 121 | vert.grad_prev = vert.grad 122 | vert.grad = m * (vert.x - vert.x_hat) 123 | vert.diagH = m * ti.Vector.one(float, 3) 124 | # elastic potential 125 | for c in self.mesh.cells: 126 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 127 | B = c.B 128 | F = Ds @ B 129 | para = c.W * self.dt ** 2 130 | dPsidx = para * self.compute_dPsidx(F, B, self.mu, self.la) 131 | diagH_d2Psidx2 = para * self.compute_diag_d2Psidx2(F, B, self.mu, self.la) 132 | for i in range(4): 133 | c.verts[i].grad += ti.Vector([dPsidx[3 * i], dPsidx[3 * i +1], dPsidx[3 * i + 2]], float) 134 | tmp = ti.Vector([diagH_d2Psidx2[3 * i], diagH_d2Psidx2[3 * i + 1], diagH_d2Psidx2[3 * i + 2]]) 135 | tmp = ti.max(tmp ,0.0) 136 | c.verts[i].diagH += tmp 137 | #ipc potential 138 | for k,j in self.cid: 139 | pair = self.cid[k,j] 140 | ids = pair.a 141 | dist = pair.b 142 | cord = pair.c 143 | t = pair.d 144 | dist2 = dist **2 145 | bg = self.barrier_g(dist) 146 | para = bg / dist 147 | para0 = (self.barrier_H(dist) - para) / dist2 148 | for i in range(4): 149 | CORD = cord[i] 150 | ID = ids[i] 151 | self.mesh.verts.grad[ID] += para * CORD * t 152 | diag_tmp = CORD * CORD * (para0 * t * t + para * ti.Vector.one(float, 3)) 153 | diag_tmp_spd = ti.max(diag_tmp,0.0) 154 | self.mesh.verts.diagH[ID] += diag_tmp_spd 155 | 156 | @ti.kernel 157 | def compute_pHp(self)->float: 158 | ret = 0.0 159 | for vert in self.mesh.verts: 160 | ret += vert.p.norm_sqr() * vert.m 161 | for c in self.mesh.cells: 162 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 163 | B = c.B 164 | F = Ds @ B 165 | d = ti.Vector.zero(float, 12) 166 | d[0:3] = c.verts[0].p 167 | d[3:6] = c.verts[1].p 168 | d[6:9] = c.verts[2].p 169 | d[9:12] = c.verts[3].p 170 | tmp = self.compute_p_d2Psidx2_p(F, B, d, self.mu, self.la) 171 | ret += c.W * self.dt ** 2 * ti.max(tmp, 0.0) 172 | 173 | for k,j in self.cid: 174 | pair = self.cid[k,j] 175 | ids = pair.a 176 | dist = pair.b 177 | cord = pair.c 178 | t = pair.d 179 | dist2 = dist * dist 180 | bg = self.barrier_g(dist) 181 | para1 = bg / dist 182 | para0 = (self.barrier_H(dist) - para1) / dist2 183 | p_tmp = ti.Vector.zero(float, 12) 184 | p_tmp[0:3] = self.mesh.verts.p[ids[0]] 185 | p_tmp[3:6] = self.mesh.verts.p[ids[1]] 186 | p_tmp[6:9] = self.mesh.verts.p[ids[2]] 187 | p_tmp[9:12] = self.mesh.verts.p[ids[3]] 188 | dtdx_t = compute_dtdx_t(t, cord) 189 | pHp_0 = para0 * ( p_tmp.dot(dtdx_t) ** 2) 190 | d_dtdx = compute_d_dtdx(p_tmp, cord) 191 | pHp_1 = para1 * d_dtdx.norm_sqr() 192 | pHp = pHp_0 + pHp_1 193 | ret += ti.max(pHp, 0.0) 194 | return ret 195 | 196 | @ti.kernel 197 | def add_E_ground_barrier(self) -> float: 198 | E = 0.0 199 | min_dist = 1e-2 * self.dHat 200 | for i in range(self.n_boundary_points): 201 | p = self.boundary_points[i] 202 | x_a0 = self.mesh.verts.x[p] 203 | dist = x_a0[1] - self.ground 204 | if dist < self.dHat: 205 | if dist < min_dist: 206 | dist = min_dist 207 | E += self.barrier_E(dist) 208 | return E 209 | 210 | @ti.kernel 211 | def add_grad_and_diagH_ground_barrier(self): 212 | # set the boundary condition with ipc, min_dist is used to prevent generating too large force 213 | min_dist = 1e-2 * self.dHat 214 | for i in range(self.n_boundary_points): 215 | p = self.boundary_points[i] 216 | x_a0 = self.mesh.verts.x[p] 217 | dist = x_a0[1] - self.ground 218 | if dist < self.dHat: 219 | if dist <= min_dist: 220 | self.mesh.verts.x[p][1] = self.ground + min_dist 221 | dist = min_dist 222 | self.mesh.verts.grad[p][1] += self.barrier_g(dist) 223 | self.mesh.verts.diagH[p][1] += self.barrier_H(dist) 224 | 225 | 226 | @ti.kernel 227 | def add_pHp_ground_barrier(self)->float: 228 | ret = 0.0 229 | min_dist = 1e-2 * self.dHat 230 | for i in range(self.boundary_points.shape[0]): 231 | p = self.boundary_points[i] 232 | x_a0 = self.mesh.verts.x[p] 233 | dist = x_a0[1] - self.ground 234 | if dist < self.dHat: 235 | if dist <= min_dist: 236 | dist = min_dist 237 | p_tmp = self.mesh.verts.p[p][1] 238 | ret_value = p_tmp * self.barrier_H(dist) * p_tmp 239 | ret += ret_value 240 | return ret 241 | 242 | def line_search_newton(self): 243 | gTp = self.compute_gTp() 244 | pHp = self.compute_pHp() 245 | if self.ground_barrier == 1: 246 | pHp_ground = self.add_pHp_ground_barrier() 247 | pHp += pHp_ground 248 | alpha = - gTp / pHp 249 | return alpha, gTp, pHp 250 | 251 | 252 | @ti.kernel 253 | def compute_p_inf_norm(self)->float: 254 | p_max = 0.0 255 | for vert in self.mesh.verts: 256 | p_norm = vert.p.norm() 257 | ti.atomic_max(p_max, p_norm) 258 | return p_max 259 | 260 | 261 | def step(self): 262 | print('Frame', self.frame) 263 | self.assign_xn_xhat() 264 | for iter in range(self.iter_max): 265 | self.find_cnts(PRINT=False) 266 | self.compute_grad_and_diagH() 267 | if self.ground_barrier == 1: 268 | self.add_grad_and_diagH_ground_barrier() 269 | if iter == 0: 270 | self.compute_init_p() 271 | else: 272 | self.compute_DK_direction() 273 | alpha, gTp, pHp = self.line_search_newton() 274 | p_max = self.compute_p_inf_norm() 275 | if alpha * p_max > 0.5 * self.dHat: 276 | alpha_int = alpha 277 | alpha = 0.5 * self.dHat / p_max 278 | print('alpha clamped', alpha, 'alpha init', alpha_int) 279 | self.update_x(alpha) 280 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 281 | if iter == 0: 282 | delta_E_init = delta_E 283 | if delta_E < self.epsilon * delta_E_init: 284 | print('converage at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 285 | 'gTp', gTp, 'pHp', pHp) 286 | break 287 | else: 288 | print('iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 289 | 'pHp', pHp) 290 | 291 | self.update_v_and_bound() 292 | self.frame += 1 293 | return iter 294 | 295 | @ti.kernel 296 | def line_search_clamped_newton(self,rate:float) -> (float,float,float): 297 | """ first compute newton line search , then clamp the alpha with max displacement 0.5 dHat""" 298 | pHp = 0.0 299 | gTp = 0.0 300 | p_max = 0.0 301 | for vert in self.mesh.verts: 302 | gTp += vert.grad.dot(vert.p) 303 | pHp += vert.p.norm_sqr() * vert.m 304 | p_norm = vert.p.norm() 305 | ti.atomic_max(p_max, p_norm) 306 | 307 | for c in self.mesh.cells: 308 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 309 | B = c.B 310 | F = Ds @ B 311 | p = ti.Vector.zero(float, 12) 312 | p[0:3] = c.verts[0].p 313 | p[3:6] = c.verts[1].p 314 | p[6:9] = c.verts[2].p 315 | p[9:12] = c.verts[3].p 316 | tmp = self.compute_p_d2Psidx2_p(F, B, p, self.mu, self.la) 317 | pHp += c.W * self.dt ** 2 * ti.max(tmp, 0.0) 318 | for k,j in self.cid: 319 | pair = self.cid[k,j] 320 | ids = pair.a 321 | dist = pair.b 322 | cord = pair.c 323 | t = pair.d 324 | dist2 = dist * dist 325 | bg = self.barrier_g(dist) 326 | para1 = bg / dist 327 | para0 = (self.barrier_H(dist) - para1) / dist2 328 | p_tmp = ti.Vector.zero(float, 12) 329 | p_tmp[0:3] = self.mesh.verts.p[ids[0]] 330 | p_tmp[3:6] = self.mesh.verts.p[ids[1]] 331 | p_tmp[6:9] = self.mesh.verts.p[ids[2]] 332 | p_tmp[9:12] = self.mesh.verts.p[ids[3]] 333 | dtdx_t = compute_dtdx_t(t, cord) 334 | pHp_0 = para0 * ( p_tmp.dot(dtdx_t) ** 2) 335 | p_dtdx = compute_d_dtdx(p_tmp, cord) 336 | pHp_1 = para1 * p_dtdx.norm_sqr() 337 | pHp += ti.max(pHp_0+pHp_1, 0.0) 338 | alpha = - gTp / pHp 339 | if alpha * p_max > rate * self.dHat: 340 | alpha_int = alpha 341 | alpha = rate * self.dHat / p_max 342 | print('alpha clamped', alpha, 'alpha init', alpha_int) 343 | for vert in self.mesh.verts: 344 | vert.x += alpha * vert.p 345 | return (alpha, gTp, pHp) 346 | 347 | 348 | 349 | def step_dirichlet(self): 350 | print('Frame', self.frame) 351 | self.assign_xn_xhat() 352 | for iter in range(self.iter_max): 353 | self.find_cnts(PRINT=False) 354 | self.compute_grad_and_diagH() 355 | self.dirichlet_grad() 356 | if self.ground_barrier == 1: 357 | self.add_grad_and_diagH_ground_barrier() 358 | if iter == 0: 359 | self.compute_init_p() 360 | else: 361 | self.compute_DK_direction() 362 | alpha, gTp, pHp = self.line_search_newton() 363 | p_max = self.compute_p_inf_norm() 364 | if alpha * p_max > 0.5 * self.dHat: 365 | alpha_int = alpha 366 | alpha = 0.5 * self.dHat / p_max 367 | print('alpha clamped', alpha, 'alpha init', alpha_int) 368 | self.update_x(alpha) 369 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 370 | if iter == 0: 371 | delta_E_init = delta_E 372 | if delta_E < self.epsilon * delta_E_init: 373 | print('converage at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 374 | 'gTp', gTp, 'pHp', pHp) 375 | break 376 | else: 377 | print('iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 378 | 'pHp', pHp) 379 | 380 | self.update_v_and_bound() 381 | self.frame += 1 382 | return iter 383 | 384 | @ti.kernel 385 | def check_inverse(self)->int: 386 | # check is there any inversion 387 | ret = 0 388 | for c in self.mesh.cells: 389 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 390 | F = Ds @ c.B 391 | J = F.determinant() 392 | if J < -1e-6: 393 | ret = 1 394 | return ret 395 | -------------------------------------------------------------------------------- /demo/PNCG_supplemental_document.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/demo/PNCG_supplemental_document.pdf -------------------------------------------------------------------------------- /demo/cubic_demos.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | current_file_path = os.path.abspath(__file__) 4 | parent_dir = os.path.dirname(os.path.dirname(current_file_path)) 5 | sys.path.append(parent_dir) 6 | from algorithm.pncg_base_collision_free import * 7 | @ti.data_oriented 8 | class cubic_demos(pncg_base_deformer): 9 | """unittest of cubic squeeze rotate stretch""" 10 | def get_dirichlet_points(self): 11 | x_np = self.mesh.get_position_as_numpy() 12 | x_min = np.min(x_np[:,1]) 13 | x_max = np.max(x_np[:,1]) 14 | points_lower = x_np[:,1] == x_min 15 | points_higher = x_np[:,1] == x_max 16 | dirichlet_points = np.logical_or(points_lower,points_higher) 17 | dirichlet_points = np.int32(dirichlet_points) 18 | print(np.sum(points_lower),np.sum(points_higher),np.sum(dirichlet_points)) 19 | path = self.dict['model_paths'][0].rsplit('/',1)[0] + '/is_dirichlet.npy' 20 | np.save(path,dirichlet_points) 21 | 22 | @ti.kernel 23 | def assign_xn_xhat_squeeze(self, speed:ti.f32): 24 | for vert in self.mesh.verts: 25 | vert.x_n = vert.x 26 | if vert.is_dirichlet == 1: 27 | if vert.x[1] == 0.25: 28 | # lower 29 | vert.x_hat = vert.x 30 | else: 31 | vert.x[1] -= speed * self.dt 32 | vert.x_hat = vert.x 33 | else: 34 | vert.x_hat = vert.x + self.dt * vert.v 35 | 36 | @ti.kernel 37 | def assign_xn_xhat_stretch(self, speed:ti.f32): 38 | for vert in self.mesh.verts: 39 | vert.x_n = vert.x 40 | if vert.is_dirichlet == 1: 41 | if vert.x[1] == 0.25: 42 | # lower 43 | vert.x_hat = vert.x 44 | else: 45 | vert.x[1] += speed * self.dt 46 | vert.x_hat = vert.x 47 | else: 48 | vert.x_hat = vert.x + self.dt * vert.v 49 | 50 | @ti.kernel 51 | def assign_xn_xhat_rotate(self, speed:ti.f32, frame:ti.i32): 52 | for vert in self.mesh.verts: 53 | vert.x_n = vert.x 54 | if vert.is_dirichlet == 1: 55 | if vert.x[1] == 0.25: 56 | # lower 57 | vert.x_hat = vert.x 58 | else: 59 | angle = frame * speed * ti.math.pi 60 | # print('frame',self.frame,'angle',angle,ti.cos(angle),ti.sin(angle)) 61 | rotate_matrix = ti.Matrix([[ti.cos(angle), 0, ti.sin(angle)], [0, 1, 0], [-ti.sin(angle), 0, ti.cos(angle)]],float) 62 | center_point = ti.Vector([0.5,vert.x[1],-0.5],float) 63 | p_c = vert.x - center_point 64 | p_rot = rotate_matrix @ p_c 65 | p_final = p_rot + center_point 66 | # p_final[1] += speed * 30 67 | # print(vert.x, p_rot,p_final) 68 | vert.x = p_final 69 | vert.x_hat = vert.x 70 | else: 71 | vert.x_hat = vert.x + self.dt * vert.v 72 | 73 | def step(self): 74 | print('Frame', self.frame) 75 | if self.frame < 70: 76 | self.assign_xn_xhat_squeeze(0.05) 77 | elif self.frame < 500: 78 | self.assign_xn_xhat_stretch(0.05) 79 | else: 80 | self.assign_xn_xhat_rotate(1e-5,self.frame-500) 81 | self.compute_grad_and_diagH() 82 | self.dirichlet_grad() 83 | self.compute_init_p() 84 | alpha, gTp, pHp = self.compute_newton_alpha() 85 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 86 | delta_E_init = delta_E 87 | for iter in range(self.iter_max): 88 | if delta_E < self.epsilon * delta_E_init: 89 | break 90 | # else: 91 | # print('iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 'pHp', 92 | # pHp) 93 | self.compute_grad_and_diagH() 94 | self.dirichlet_grad() 95 | self.compute_DK_direction() 96 | alpha, gTp, pHp = self.compute_newton_alpha() 97 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 98 | print('finish at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', 99 | gTp, 'pHp', pHp) 100 | self.update_v_and_bound() 101 | self.frame += 1 102 | return iter 103 | 104 | if __name__ == '__main__': 105 | ti.init(arch=ti.gpu, default_fp=ti.f32)#, device_memory_fraction=0.9)#,kernel_profiler=True),advanced_optimization=True,fast_math=True) 106 | demos = ['cube','cube_10','cube_20','cube_40'] 107 | demo = demos[3] 108 | deformer = cubic_demos(demo = demo) 109 | print(deformer.dict) 110 | deformer.get_dirichlet_points() 111 | deformer.init_dirichlet() 112 | print('init finish') 113 | deformer.visual() 114 | # deformer.save_new(1000,SAVE_OBJ=False) 115 | -------------------------------------------------------------------------------- /demo/demo_low_res.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/demo/demo_low_res.mp4 -------------------------------------------------------------------------------- /demo/drag_armadillo_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | current_file_path = os.path.abspath(__file__) 4 | parent_dir = os.path.dirname(os.path.dirname(current_file_path)) 5 | sys.path.append(parent_dir) 6 | from algorithm.pncg_base_collision_free import * 7 | class DK_dirichlet(pncg_base_deformer): 8 | def init_dirichlet(self): 9 | print('init dirichlet') 10 | self.mesh.verts.place({'is_dirichlet': ti.i32}) 11 | path = '../model/mesh/Armadillo13K/is_dirichlet.npy' 12 | dirichlet_np = np.load(path) 13 | print('load np') 14 | print(dirichlet_np.shape, self.n_verts) 15 | self.mesh.verts.is_dirichlet.from_numpy(dirichlet_np) 16 | print('init finish') 17 | 18 | def get_dirichlet_points(self): 19 | x_np = self.mesh.get_position_as_numpy() 20 | x_min = np.min(x_np[:,1]) 21 | x_max = np.max(x_np[:,1]) 22 | points_lower = (x_np[:,1] - x_min) < 1.5 23 | points_higher = (x_max - x_np[:,1]) < 1.5 24 | dirichlet_points = np.logical_or(points_lower,points_higher) 25 | dirichlet_points = np.int32(dirichlet_points) 26 | print(np.sum(points_lower),np.sum(points_higher),np.sum(dirichlet_points)) 27 | path = self.dict['model_paths'][0].rsplit('/',1)[0] + '/is_dirichlet.npy' 28 | np.save(path,dirichlet_points) 29 | @ti.kernel 30 | def assign_xn_xhat_2(self, force: ti.f32): 31 | ti.mesh_local(self.mesh.verts.x) 32 | for vert in self.mesh.verts: 33 | vert.x_n = vert.x 34 | vert.x_hat = vert.x + self.dt * vert.v 35 | vert.x_hat[2] += self.dt * self.dt * force / vert.m 36 | 37 | def step(self): 38 | print('Frame', self.frame) 39 | if self.frame < 80: 40 | self.assign_xn_xhat_2(5000.0) 41 | else: 42 | self.assign_xn_xhat() 43 | self.compute_grad_and_diagH() 44 | self.dirichlet_grad() 45 | self.compute_init_p() 46 | alpha, gTp, pHp = self.compute_newton_alpha() 47 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 48 | delta_E_init = delta_E 49 | for iter in range(self.iter_max): 50 | if delta_E < self.epsilon * delta_E_init: 51 | break 52 | 53 | self.compute_grad_and_diagH() 54 | self.dirichlet_grad() 55 | self.compute_DK_direction() 56 | alpha, gTp, pHp = self.compute_newton_alpha() 57 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 58 | print('converage at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', 59 | gTp, 'pHp', pHp) 60 | self.update_v_and_bound() 61 | self.frame += 1 62 | return iter 63 | 64 | if __name__ == '__main__': 65 | ti.init(arch=ti.gpu, default_fp=ti.f32) 66 | demo = 'armadillo_collision_free' 67 | deformer = DK_dirichlet(demo = demo) 68 | deformer.get_dirichlet_points() 69 | deformer.init_dirichlet() 70 | deformer.visual() 71 | 72 | -------------------------------------------------------------------------------- /demo/n_E_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | current_file_path = os.path.abspath(__file__) 4 | parent_dir = os.path.dirname(os.path.dirname(current_file_path)) 5 | sys.path.append(parent_dir) 6 | from algorithm.pncg_base_ipc import * 7 | 8 | @ti.data_oriented 9 | class pncg_index(pncg_ipc_deformer): 10 | def set_index(self): 11 | # initialize model 12 | self.mesh.verts.place({'index': ti.i32}) 13 | self.per_vertex_color = ti.Vector.field(3, dtype=float,shape=self.n_verts) 14 | self.object_size = 1046 15 | self.N_object = int(self.n_verts / self.object_size) 16 | self.init_index() 17 | 18 | self.frame = 0 19 | self.CNT = 0 20 | 21 | @ti.kernel 22 | def init_index(self): 23 | # setting index for each vertex 24 | for vert in self.mesh.verts: 25 | index = vert.id // self.object_size 26 | vert.index = index 27 | 28 | @ti.kernel 29 | def compute_DK_index(self): 30 | # compute DK direction for each object 31 | g_Py_index = ti.Vector.zero(float, self.N_object) 32 | y_p_index = ti.Vector.zero(float, self.N_object) 33 | y_Py_index = ti.Vector.zero(float, self.N_object) 34 | g_p_index = ti.Vector.zero(float, self.N_object) 35 | beta_index = ti.Vector.zero(float, self.N_object) 36 | for vert in self.mesh.verts: 37 | index = vert.index 38 | y = vert.grad - vert.grad_prev 39 | Py = y / vert.diagH 40 | y_p_index[index] += y.dot(vert.p) 41 | g_Py_index[index] += vert.grad.dot(Py) 42 | y_Py_index[index] += y.dot(Py) 43 | g_p_index[index] += vert.grad.dot(vert.p) 44 | 45 | for i in range(self.N_object): 46 | beta_index[i] = (g_Py_index[i] - y_Py_index[i] * g_p_index[i] / y_p_index[i]) / y_p_index[i] 47 | for vert in self.mesh.verts: 48 | index = vert.index 49 | vert.p = - vert.grad / vert.diagH + beta_index[index] * vert.p 50 | 51 | @ti.kernel 52 | def compute_alpha_index_and_update_x(self)->float: 53 | gTp_index = ti.Vector.zero(float, self.N_object) 54 | pHp_index = ti.Vector.zero(float, self.N_object) 55 | alpha_index = ti.Vector.zero(float, self.N_object) 56 | p_max_index = ti.Vector.zero(float, self.N_object) 57 | for vert in self.mesh.verts: 58 | index = vert.index 59 | gTp_index[index] += vert.grad.dot(vert.p) 60 | 61 | for vert in self.mesh.verts: 62 | index = vert.index 63 | pHp_index[index] += vert.p.norm_sqr() * vert.m 64 | 65 | for c in self.mesh.cells: 66 | index = c.verts[0].index 67 | Ds = ti.Matrix.cols([c.verts[i].x - c.verts[0].x for i in ti.static(range(1, 4))]) 68 | B = c.B 69 | F = Ds @ B 70 | p = ti.Vector.zero(float, 12) 71 | p[0:3] = c.verts[0].p 72 | p[3:6] = c.verts[1].p 73 | p[6:9] = c.verts[2].p 74 | p[9:12] = c.verts[3].p 75 | tmp = self.compute_p_d2Psidx2_p(F, B, p, self.mu, self.la) 76 | pHp_index[index] += c.W * self.dt ** 2 * ti.max(tmp, 0.0) 77 | 78 | for k,j in self.cid: 79 | pair = self.cid[k,j] 80 | ids = pair.a 81 | dist = pair.b 82 | cord = pair.c 83 | t = pair.d 84 | dist2 = dist * dist 85 | bg = self.barrier_g(dist) 86 | para1 = bg / dist 87 | para0 = (self.barrier_H(dist) - para1) / dist2 88 | p_tmp = ti.Vector.zero(float, 12) 89 | p_tmp[0:3] = self.mesh.verts.p[ids[0]] 90 | p_tmp[3:6] = self.mesh.verts.p[ids[1]] 91 | p_tmp[6:9] = self.mesh.verts.p[ids[2]] 92 | p_tmp[9:12] = self.mesh.verts.p[ids[3]] 93 | dtdx_t = compute_dtdx_t(t, cord) 94 | pHp_0 = para0 * ( p_tmp.dot(dtdx_t) ** 2 ) 95 | d_dtdx = compute_d_dtdx(p_tmp, cord) 96 | pHp_1 = para1 * d_dtdx.norm_sqr() 97 | pHp = ti.max(pHp_0 + pHp_1,0.0) 98 | index0 = self.mesh.verts.index[ids[0]] 99 | index1 = self.mesh.verts.index[ids[2]] 100 | pHp_index[index0] += pHp * 0.5 # 平分pHp 101 | pHp_index[index1] += pHp * 0.5 102 | 103 | min_dist = 1e-2 * self.dHat 104 | for i in range(self.boundary_points.shape[0]): 105 | p = self.boundary_points[i] 106 | index = self.mesh.verts.index[p] 107 | x_a0 = self.mesh.verts.x[p] 108 | dist = x_a0[1] - self.ground 109 | if dist < self.dHat: 110 | if dist <= min_dist: 111 | dist = min_dist 112 | p_tmp = self.mesh.verts.p[p][1] 113 | ret_value = p_tmp * self.barrier_H(dist) * p_tmp 114 | pHp_index[index] += ret_value 115 | 116 | for vert in self.mesh.verts: 117 | index = vert.index 118 | d_norm = vert.p.norm() 119 | ti.atomic_max(p_max_index[index], d_norm) 120 | # print('p_max', p_max_index) 121 | Delta_E = 0.0 122 | for i in range(self.N_object): 123 | alpha_i = - gTp_index[i] / pHp_index[i] 124 | if alpha_i * p_max_index[i] > 0.5 * self.dHat: 125 | alpha_index[i] = 0.5 * self.dHat / p_max_index[i] 126 | else: 127 | alpha_index[i] = alpha_i 128 | Delta_E -= (alpha_index[i] * gTp_index[i] + 0.5 * alpha_index[i]**2 * pHp_index[i]) 129 | 130 | for vert in self.mesh.verts: 131 | index = vert.index 132 | alpha = alpha_index[index] 133 | vert.x += alpha * vert.p 134 | return Delta_E 135 | 136 | def step(self): 137 | print('Frame', self.frame) 138 | self.assign_xn_xhat() 139 | for iter in range(self.iter_max): 140 | # print('iter', iter) 141 | self.find_cnts() 142 | self.compute_grad_and_diagH() 143 | if self.ground_barrier == 1: 144 | self.add_grad_and_diagH_ground_barrier() 145 | if iter == 0: 146 | self.compute_init_p() 147 | else: 148 | self.compute_DK_index() 149 | delta_E = self.compute_alpha_index_and_update_x() 150 | if iter == 0: 151 | delta_E_init = delta_E 152 | if delta_E < self.epsilon * delta_E_init: 153 | break 154 | print('finish at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E) 155 | self.update_v_and_bound() 156 | self.frame += 1 157 | return iter 158 | 159 | 160 | 161 | 162 | if __name__ == '__main__': 163 | ti.init(arch=ti.gpu, default_fp=ti.f32)#, device_memory_fraction=0.9)#, kernel_profiler=True) 164 | demo = 'eight_E_drop_demo_contact' 165 | ipc_deformer = pncg_index(demo=demo) 166 | ipc_deformer.set_index() 167 | ipc_deformer.visual() 168 | # ipc_deformer.save_new(500, SAVE_OBJ=True) -------------------------------------------------------------------------------- /demo/squeeze_armadillo_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | current_file_path = os.path.abspath(__file__) 4 | parent_dir = os.path.dirname(os.path.dirname(current_file_path)) 5 | sys.path.append(parent_dir) 6 | from algorithm.pncg_base_ipc import * 7 | 8 | @ti.data_oriented 9 | class squeeze_armadillo_demo(pncg_ipc_deformer): 10 | def init_visual(self): 11 | self.boundary_barriers = ti.Vector.field(1, dtype=ti.f32, shape=(6,)) # left, right, down, up, back, front 12 | self.per_vertex_color = ti.Vector.field(3, dtype=ti.f32,shape=self.n_verts) 13 | self.lines = ti.Vector.field(3, dtype=ti.f32,shape=24) 14 | self.set_barrier_init_value(5.0) # set boundary barrier 15 | self.set_lines() 16 | self.set_color() # set color of each object 17 | self.frame = 0 18 | 19 | @ti.kernel 20 | def set_color(self): 21 | n = 13054 22 | for i in range(n): 23 | self.per_vertex_color[i] = ti.Vector([0.473, 0.643, 0.8],ti.f32) 24 | for i in range(n, 2 * n): 25 | self.per_vertex_color[i] = ti.Vector([0.233, 0.8, 0.409],ti.f32) 26 | for i in range(2 * n, 3 * n): 27 | self.per_vertex_color[i] = ti.Vector([0.8, 0.466, 0.565], ti.f32) 28 | for i in range(3 * n , 4 * n): 29 | self.per_vertex_color[i] = ti.Vector([0.8, 0.8 ,0.8], ti.f32) 30 | @ti.kernel 31 | def set_lines(self): 32 | N = 0 33 | ti.loop_config(serialize=True) 34 | for i in ti.static(range(2)): 35 | for j in ti.static(range(2)): 36 | for k in ti.static(range(2)): 37 | self.lines[N] = ti.Vector( 38 | [self.boundary_barriers[i], self.boundary_barriers[2 + j], self.boundary_barriers[4 + k]], 39 | ti.f32) 40 | N+=1 41 | ti.loop_config(serialize=True) 42 | for i in ti.static(range(2)): 43 | for k in ti.static(range(2)): 44 | for j in ti.static(range(2)): 45 | self.lines[N] = ti.Vector( 46 | [self.boundary_barriers[i], self.boundary_barriers[2 + j], self.boundary_barriers[4 + k]], 47 | ti.f32) 48 | N+=1 49 | ti.loop_config(serialize=True) 50 | for k in ti.static(range(2)): 51 | for j in ti.static(range(2)): 52 | for i in ti.static(range(2)): 53 | # self.lines[i*4+j*2+k] = ti.Vector([self.boundary_barriers[i], self.boundary_barriers[2+j], self.boundary_barriers[4+k]], ti.f32) 54 | self.lines[N] = ti.Vector( 55 | [self.boundary_barriers[i], self.boundary_barriers[2 + j], self.boundary_barriers[4 + k]], 56 | ti.f32) 57 | N+=1 58 | 59 | def set_barrier_init_value(self, value): 60 | node_np = self.mesh.verts.x.to_numpy() 61 | node_box = ti.Vector([np.min(node_np[:, 0]), np.max(node_np[:, 0]), np.min(node_np[:, 1]), np.max(node_np[:, 1]), 62 | np.min(node_np[:, 2]), np.max(node_np[:, 2])], ti.f32) 63 | self.boundary_barriers[0][0] = node_box[0] - value 64 | self.boundary_barriers[1][0] = node_box[1] + value 65 | self.boundary_barriers[2][0] = node_box[2] - value 66 | self.boundary_barriers[3][0] = node_box[3] + value 67 | self.boundary_barriers[4][0] = node_box[4] - value 68 | self.boundary_barriers[5][0] = node_box[5] + value 69 | 70 | def update_boundary(self, speed): 71 | self.boundary_barriers[0][0] += speed 72 | self.boundary_barriers[1][0] -= speed 73 | self.boundary_barriers[3][0] -= speed 74 | self.boundary_barriers[4][0] += speed 75 | self.boundary_barriers[5][0] -= speed 76 | 77 | @ti.kernel 78 | def add_grad_and_diagH_barriers(self): 79 | min_dist = 1e-3 * self.dHat 80 | for vert in self.mesh.verts: 81 | x_a0 = vert.x 82 | dist_left = x_a0[0] - self.boundary_barriers[0][0] 83 | dist_right = self.boundary_barriers[1][0] - x_a0[0] 84 | dist_down = x_a0[1] - self.boundary_barriers[2][0] 85 | dist_up = self.boundary_barriers[3][0] - x_a0[1] 86 | dist_back = x_a0[2] - self.boundary_barriers[4][0] 87 | dist_front = self.boundary_barriers[5][0] - x_a0[2] 88 | 89 | if dist_left < self.dHat: 90 | if dist_left < min_dist: 91 | vert.x[0] = self.boundary_barriers[0][0] + min_dist 92 | dist_left = min_dist 93 | vert.grad[0] += self.barrier_g(dist_left) 94 | vert.diagH[0] += self.barrier_H(dist_left) 95 | elif dist_right < self.dHat: 96 | if dist_right < min_dist: 97 | vert.x[0] = self.boundary_barriers[1][0] - min_dist 98 | dist_right = min_dist 99 | vert.grad[0] -= self.barrier_g(dist_right) 100 | vert.diagH[0] += self.barrier_H(dist_right) 101 | if dist_down < self.dHat: 102 | if dist_down < min_dist: 103 | vert.x[1] = self.boundary_barriers[2][0] + min_dist 104 | dist_down = min_dist 105 | vert.grad[1] += self.barrier_g(dist_down) 106 | vert.diagH[1] += self.barrier_H(dist_down) 107 | elif dist_up < self.dHat: 108 | if dist_up < min_dist: 109 | vert.x[1] = self.boundary_barriers[3][0] - min_dist 110 | dist_up = min_dist 111 | vert.grad[1] -= self.barrier_g(dist_up) 112 | vert.diagH[1] += self.barrier_H(dist_up) 113 | if dist_back < self.dHat: 114 | if dist_back < min_dist: 115 | vert.x[2] = self.boundary_barriers[4][0] + min_dist 116 | dist_back = min_dist 117 | vert.grad[2] += self.barrier_g(dist_back) 118 | vert.diagH[2] += self.barrier_H(dist_back) 119 | elif dist_front < self.dHat: 120 | if dist_front < min_dist: 121 | vert.x[2] = self.boundary_barriers[5][0] - min_dist 122 | dist_front = min_dist 123 | vert.grad[2] -= self.barrier_g(dist_front) 124 | vert.diagH[2] += self.barrier_H(dist_front) 125 | 126 | def step(self): 127 | print('Frame', self.frame) 128 | if self.frame < 450: 129 | self.update_boundary(0.2) 130 | elif self.frame < 550: 131 | self.update_boundary(0.1) 132 | else: 133 | self.set_barrier_init_value(500) 134 | self.assign_xn_xhat() 135 | for iter in range(self.iter_max): 136 | self.find_cnts() 137 | self.compute_grad_and_diagH() 138 | if self.ground_barrier == 1: 139 | self.add_grad_and_diagH_barriers() 140 | if iter == 0: 141 | self.compute_init_p() 142 | else: 143 | self.compute_DK_direction() 144 | alpha, gTp, pHp = self.line_search_clamped_newton(0.5) 145 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 146 | if iter == 0: 147 | delta_E_init = delta_E 148 | if delta_E < self.epsilon * delta_E_init: 149 | # print('converage at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 150 | # 'gTp', gTp, 'pHp', pHp) 151 | break 152 | # else: 153 | # print('iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 154 | # 'pHp', pHp) 155 | print('converage at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 156 | 'gTp', gTp, 'pHp', pHp) 157 | self.update_v() 158 | self.frame += 1 159 | return iter 160 | 161 | def visual(self): 162 | window = ti.ui.Window("Visualization", (800, 600), vsync=True) 163 | dir = '../demo_results/final/' + self.demo + '/' 164 | if not os.path.exists(dir): 165 | os.makedirs(dir) 166 | canvas = window.get_canvas() 167 | scene = ti.ui.Scene() 168 | camera = ti.ui.Camera() 169 | camera.position(self.camera_position[0], self.camera_position[1], self.camera_position[2]) 170 | camera.lookat(self.camera_lookat[0], self.camera_lookat[1], self.camera_lookat[2]) 171 | camera.fov(75) 172 | canvas.set_background_color(color=(0.2, 0.2, 0.2)) 173 | point_light_color = (0.5,0.5,0.5) 174 | while window.running: 175 | if window.get_event(ti.ui.PRESS): 176 | if window.event.key == 'r': 177 | self.restart() 178 | if window.event.key == 'b': 179 | break 180 | self.set_lines() 181 | camera.track_user_inputs(window, movement_speed=1.0, hold_key=ti.ui.RMB) 182 | scene.set_camera(camera) 183 | scene.ambient_light((0.1, 0.1, 0.1)) 184 | for light_pos in self.point_lights: 185 | scene.point_light(pos=light_pos, color=point_light_color) 186 | scene.mesh_instance(self.mesh.verts.x, self.indices, show_wireframe=False, per_vertex_color=self.per_vertex_color) 187 | scene.lines(self.lines, color = (1.0, 1.0, 1.0), width = 1.0) 188 | 189 | canvas.scene(scene) 190 | window.show() 191 | self.step() 192 | 193 | if __name__ == '__main__': 194 | ti.init(arch=ti.gpu, default_fp=ti.f32)#, device_memory_fraction=0.9)#, kernel_profiler=True) 195 | demo = 'squeeze_four_armadillo' 196 | ipc_deformer = squeeze_armadillo_demo(demo=demo) 197 | ipc_deformer.init_visual() 198 | print('init finish') 199 | ipc_deformer.find_cnts(PRINT=True) 200 | ipc_deformer.visual() -------------------------------------------------------------------------------- /demo/twist_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | current_file_path = os.path.abspath(__file__) 4 | parent_dir = os.path.dirname(os.path.dirname(current_file_path)) 5 | sys.path.append(parent_dir) 6 | from algorithm.pncg_base_ipc import * 7 | 8 | @ti.data_oriented 9 | class twist_demo(pncg_ipc_deformer): 10 | @ti.kernel 11 | def init_dirichlet_assign_speed(self,speed_angle:float): 12 | speed = speed_angle / 180.0 13 | ti.mesh_local(self.mesh.verts.x) 14 | for vert in self.mesh.verts: 15 | if vert.is_dirichlet == 1: 16 | x_id = vert.x 17 | a = x_id[0] 18 | b = x_id[1] 19 | c = x_id[2] 20 | angle = ti.atan2(b, c) 21 | angle += speed * ti.math.pi * (1 if a < 0 else -1) 22 | radius = ti.sqrt(b * b + c * c) 23 | vert.x[1] = radius * ti.sin(angle) 24 | vert.x[2] = radius * ti.cos(angle) 25 | vert.x_hat = vert.x 26 | else: 27 | vert.x_hat = vert.x + vert.v * self.dt 28 | vert.x_n = vert.x 29 | 30 | def step(self): 31 | print('Frame', self.frame) 32 | self.init_dirichlet_assign_speed(2.88) 33 | for iter in range(self.iter_max): 34 | self.find_cnts_iter(iter) 35 | self.compute_grad_and_diagH() 36 | self.dirichlet_grad() 37 | if iter == 0: 38 | self.compute_init_p() 39 | else: 40 | self.compute_DK_direction() 41 | alpha, gTp, pHp = self.line_search_clamped_newton(1.0) 42 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 43 | if iter == 0: 44 | delta_E_init = delta_E 45 | if delta_E < self.epsilon * delta_E_init and iter > 20: 46 | # print('converage at iter', iter, '!') 47 | break 48 | print('finish at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 49 | 'pHp', pHp) 50 | # print('dcd collision', self.check_dcd(),'inverse', self.check_inverse()) 51 | self.update_v() 52 | self.frame += 1 53 | return iter 54 | 55 | if __name__ == '__main__': 56 | ti.init(arch=ti.gpu, default_fp=ti.f32) 57 | demos = ['twist_mat150','twist_rods'] 58 | ipc_deformer = twist_demo(demo=demos[1]) 59 | ipc_deformer.visual() -------------------------------------------------------------------------------- /demo/unittest_demos.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | current_file_path = os.path.abspath(__file__) 4 | parent_dir = os.path.dirname(os.path.dirname(current_file_path)) 5 | sys.path.append(parent_dir) 6 | from algorithm.pncg_base_ipc import * 7 | @ti.data_oriented 8 | class unittest_demos(pncg_ipc_deformer): 9 | def init_dirichlet(self): 10 | self.mesh.verts.place({'is_dirichlet': ti.i32}) 11 | self.per_vertex_color = ti.Vector.field(3, dtype=float,shape=self.n_verts) 12 | self.set_pertex_color() 13 | obj_down = self.demo.split('_')[1] 14 | if obj_down == 'cube': 15 | self.fix_obj_down(8) 16 | elif obj_down == 'spike': 17 | self.fix_obj_down(5) 18 | elif obj_down == 'wedge': 19 | self.fix_obj_down(6) 20 | elif obj_down == 'crack': 21 | self.fix_obj_down(40) 22 | elif obj_down == 'edge': 23 | self.fix_obj_down(15) 24 | elif obj_down == 'cliff': 25 | self.fix_obj_down(8) 26 | elif obj_down == 'cubes': 27 | self.fix_obj_down(24) 28 | 29 | @ti.kernel 30 | def set_pertex_color(self): 31 | for i in range(self.n_verts): 32 | self.per_vertex_color[i] = ti.Vector([0.1,0.2,0.5],float) 33 | 34 | @ti.kernel 35 | def fix_obj_down(self,n:ti.i32): 36 | for i in range(n): 37 | self.mesh.verts.is_dirichlet[i] = 1 38 | self.per_vertex_color[i] = ti.Vector([0.5,0.5,0.5],float) 39 | 40 | @ti.kernel 41 | def dirichlet_grad(self): 42 | for vert in self.mesh.verts: 43 | if vert.is_dirichlet == 1: 44 | vert.grad = ti.Vector([0, 0, 0]) 45 | 46 | 47 | def step(self): 48 | print('Frame', self.frame) 49 | self.assign_xn_xhat() 50 | for iter in range(self.iter_max): 51 | self.find_cnts(PRINT=False) 52 | self.compute_grad_and_diagH() 53 | self.dirichlet_grad() 54 | if self.ground_barrier == 1: 55 | self.add_grad_and_diagH_ground_barrier() 56 | if iter == 0: 57 | self.compute_init_p() 58 | else: 59 | self.compute_DK_direction() 60 | alpha, gTp, pHp = self.line_search_clamped_newton(0.5) 61 | delta_E = - alpha * gTp - 0.5 * alpha ** 2 * pHp 62 | if iter == 0: 63 | delta_E_init = delta_E 64 | if delta_E < self.epsilon * delta_E_init: 65 | break 66 | # else: 67 | # print('iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 'gTp', gTp, 68 | # 'pHp', pHp) 69 | print('converage at iter', iter, 'rate', delta_E / delta_E_init, 'delta_E', delta_E, 'alpha', alpha, 70 | 'gTp', gTp, 'pHp', pHp) 71 | 72 | self.update_v_and_bound() 73 | self.frame += 1 74 | return iter 75 | 76 | 77 | 78 | def visual(self): 79 | print('precombile') 80 | self.step() 81 | print('precombile finish') 82 | window = ti.ui.Window("unittests", (1920, 1080), vsync=True) 83 | dir = '../demo_results/final/' + self.demo + '/' 84 | if not os.path.exists(dir): 85 | os.makedirs(dir) 86 | canvas = window.get_canvas() 87 | canvas.set_background_color(color=(1.0, 1.0, 1.0)) 88 | # scene = ti.ui.Scene() 89 | scene = window.get_scene() 90 | camera = ti.ui.Camera() 91 | camera.position(self.camera_position[0], self.camera_position[1], self.camera_position[2]) 92 | camera.lookat(self.camera_lookat[0], self.camera_lookat[1], self.camera_lookat[2]) 93 | camera.fov(75) 94 | 95 | while window.running: 96 | if window.get_event(ti.ui.PRESS): 97 | if window.event.key == 'r': 98 | self.restart() 99 | if window.event.key == 'b': 100 | break 101 | camera.track_user_inputs(window, movement_speed=0.1, hold_key=ti.ui.RMB) 102 | scene.set_camera(camera) 103 | scene.ambient_light((1.0,1.0,1.0)) 104 | scene.mesh_instance(self.mesh.verts.x, self.indices, show_wireframe=False, per_vertex_color=self.per_vertex_color) 105 | scene.lines(self.mesh.verts.x,3.0,self.boundary_edges,color=(0.0,0.0,0.0)) 106 | canvas.scene(scene) 107 | window.show() 108 | self.step() 109 | 110 | if __name__ == '__main__': 111 | ti.init(arch=ti.gpu, default_fp=ti.f32,default_ip=ti.i32)#, device_memory_fraction=0.9)#, kernel_profiler=True) 112 | demos = ['unittest_wedge_wedge', 'unittest_wedge_spike', 'unittest_spike_spike', 113 | 'unittest_crack_spike','unittest_crack_wedge','unittest_edge_spike', 114 | 'unittest_cube_spike2','unittest_cube_wedge','unittest_edge_cube','unittest_cliff_cube'] 115 | for demo in demos: 116 | ipc_deformer = unittest_demos(demo=demo) 117 | ipc_deformer.init_dirichlet() 118 | print('init finish') 119 | ipc_deformer.visual() 120 | # ipc_deformer.save_results() 121 | -------------------------------------------------------------------------------- /math_utils/cubic_roots.py: -------------------------------------------------------------------------------- 1 | # 这部分代码本来用于实现local CCD,但是好像有bug,local CCD的结果不对。 2 | import taichi as ti 3 | 4 | @ti.func 5 | def cubic_roots(coef, x0, x1, tol=6e-4): 6 | """ 7 | implemets cubic roots as https://github.com/cemyuksel/cyCodeBase/blob/master/cyPolynomial.h 8 | Finds the roots of the cubic polynomial between x0 and x1 with tol and returns the roots. 9 | :param coef: vector([d,c,b,a]) f = a * x*x*x + b * x*x + c * x + d 10 | :param x0: x_min 11 | :param x1: x_max 12 | :param tol: 13 | :return: vector([root0,root1,root2]) if there are less than 3 roots, return 10 14 | """ 15 | ret = False 16 | # roots = ti.Vector([10,10,10], ti.f32) 17 | roots_0 = 10.0 18 | roots_1 = 10.0 19 | roots_2 = 10.0 20 | y0 = cubic_eval(coef, x0) 21 | y1 = cubic_eval(coef, x1) 22 | a = coef[3] *3 23 | b_2 = coef[2] 24 | c = coef[1] 25 | deriv = ti.Vector([c, 2*b_2, a, 0]) 26 | delta_4 = b_2*b_2 - a*c 27 | # print('delta_4', delta_4) 28 | if delta_4 > 0: 29 | d_2 = ti.sqrt(delta_4) 30 | q = - ( b_2 + d_2 * NewSign(b_2) ) 31 | rv0 = q / a 32 | rv1 = c / q 33 | xa = ti.min(rv0, rv1) 34 | xb = ti.max(rv0, rv1) 35 | # print('xa', xa, 'xb', xb, 'y0', y0, 'y1', y1, 'IsDifferentSign(y0,y1)', IsDifferentSign(y0,y1)) 36 | if IsDifferentSign(y0,y1): 37 | if xa >= x1 or xb <= x0 or ( xa <= x0 and xb >= x1 ): 38 | roots_0 = FindClosed(coef, deriv, x0, x1, y0, tol) 39 | ret = True 40 | else: 41 | if (xa >= x1 or xb <= x0) or ( xa <= x0 and xb >= x1 ): 42 | ret = True 43 | 44 | if ret == False: 45 | if xa > x0: 46 | ya = cubic_eval(coef, xa) 47 | if IsDifferentSign(y0,ya): 48 | roots_0 = FindClosed(coef, deriv, x0, xa, y0, tol) 49 | if IsDifferentSign(ya,y1) or (xb < x1 and IsDifferentSign(ya, cubic_eval(coef, xb))): 50 | defPoly0,defPoly1,defPoly2 = PolynomialDeflate(coef, roots_0) 51 | roots_1, roots_2 = QuadraticRoots(defPoly0, defPoly1, defPoly2, xa, x1) 52 | elif xb < x1: 53 | yb = cubic_eval(coef, xb) 54 | if IsDifferentSign(ya,yb): 55 | roots_0 = FindClosed(coef, deriv, xa, xb, ya, tol) 56 | if IsDifferentSign(yb,y1): 57 | defPoly0, defPoly1, defPoly2 = PolynomialDeflate(coef, roots_0) 58 | roots_1, roots_2 = QuadraticRoots(defPoly0, defPoly1, defPoly2, xb, x1) 59 | elif IsDifferentSign(yb,y1): 60 | roots_0 = FindClosed(coef, deriv, xb, x1, yb, tol) 61 | elif IsDifferentSign(ya,y1): 62 | roots_0 = FindClosed(coef, deriv, xa, x1, ya, tol) 63 | else: 64 | yb = cubic_eval(coef, xb) 65 | if IsDifferentSign(y0,yb): 66 | roots_0 = FindClosed(coef, deriv, x0, xb, y0, tol) 67 | if IsDifferentSign(yb,y1): 68 | defPoly0, defPoly1, defPoly2 = PolynomialDeflate(coef, roots_0) 69 | roots_1, roots_2 = QuadraticRoots(defPoly0, defPoly1, defPoly2, xb, x1) 70 | elif IsDifferentSign(yb,y1): 71 | roots_0 = FindClosed(coef, deriv, xb, x1, yb, tol) 72 | elif IsDifferentSign(y0,y1): 73 | roots_0 = FindClosed(coef, deriv, x0, x1, y0, tol) 74 | return roots_0,roots_1,roots_2 75 | 76 | @ti.func 77 | def cubic_first_root(coef, x0, x1, tol=6e-4): 78 | """ 79 | Finds the first root of the cubic polynomial between x0 and x1 with tol and returns the root. 80 | :param coef: vector([d,c,b,a]) f = a * x*x*x + b * x*x + c * x + d 81 | !!check if it returns the minimal root 82 | :param x0: x_min 83 | :param x1: x_max 84 | :param tol: 85 | :return: float 86 | """ 87 | ret = False 88 | root = 10.0 89 | y0 = cubic_eval(coef, x0) 90 | y1 = cubic_eval(coef, x1) 91 | a = coef[3] * 3 92 | b_2 = coef[2] 93 | c = coef[1] 94 | deriv = ti.Vector([c, 2*b_2, a, 0]) 95 | delta_4 = b_2*b_2 - a*c 96 | if delta_4 > 0: 97 | d_2 = ti.sqrt(delta_4) 98 | q = - ( b_2 + d_2 * NewSign(b_2) ) 99 | rv0 = q / a 100 | rv1 = c / q 101 | xa = ti.min(rv0, rv1) 102 | xb = ti.max(rv0, rv1) 103 | if IsDifferentSign(y0,y1): 104 | if xa >= x1 or xb <= x0 or ( xa <= x0 and xb >= x1 ): 105 | root = FindClosed(coef, deriv, x0, x1, y0, tol) 106 | ret = True 107 | else: 108 | if (xa >= x1 or xb <= x0) or ( xa <= x0 and xb >= x1 ): 109 | ret = True 110 | 111 | if ret == False: 112 | if xa > x0: 113 | ya = cubic_eval(coef, xa) 114 | if IsDifferentSign(y0,ya): 115 | root = FindClosed(coef, deriv, x0, xa, y0, tol) 116 | elif xb < x1: 117 | yb = cubic_eval(coef, xb) 118 | if IsDifferentSign(ya,yb): 119 | root = FindClosed(coef, deriv, xa, xb, ya, tol) 120 | elif IsDifferentSign(yb,y1): 121 | root = FindClosed(coef, deriv, xb, x1, yb, tol) 122 | elif IsDifferentSign(ya,y1): 123 | root = FindClosed(coef, deriv, xa, x1, ya, tol) 124 | else: 125 | yb = cubic_eval(coef, xb) 126 | if IsDifferentSign(y0,yb): 127 | root = FindClosed(coef, deriv, x0, xb, y0, tol) 128 | elif IsDifferentSign(yb,y1): 129 | root = FindClosed(coef, deriv, xb, x1, yb, tol) 130 | elif IsDifferentSign(y0,y1): 131 | root = FindClosed(coef, deriv, x0, x1, y0, tol) 132 | return root 133 | 134 | @ti.func 135 | def CubicHasRoot(coef, x0, x1): 136 | ret = 0 137 | y0 = cubic_eval(coef, x0) 138 | y1 = cubic_eval(coef, x1) 139 | if IsDifferentSign(y0,y1): 140 | ret = 1 141 | else: 142 | a = coef[3] *3 143 | b_2 = coef[2] 144 | c = coef[1] 145 | delta_4 = b_2*b_2 - a*c 146 | if delta_4 > 0: 147 | d_2 = ti.sqrt(delta_4) 148 | q = - (b_2 + d_2 * NewSign(b_2)) 149 | rv0 = q / a 150 | rv1 = c / q 151 | xa = ti.min(rv0, rv1) 152 | xb = ti.max(rv0, rv1) 153 | if (xa >= x1 or xb <= x0) or ( xa <= x0 and xb >= x1 ): 154 | ret = 0 155 | elif xa > x0: 156 | ya = cubic_eval(coef, xa) 157 | if IsDifferentSign(y0,ya): 158 | ret = 1 159 | elif xb < x1: 160 | yb = cubic_eval(coef, xb) 161 | if IsDifferentSign(y0,yb): 162 | ret = 1 163 | elif xa <= x0: 164 | yb = cubic_eval(coef, xb) 165 | if IsDifferentSign(y0,yb): 166 | ret = 1 167 | return ret 168 | 169 | 170 | 171 | @ti.func 172 | def QuadraticRoots(defPoly0, defPoly1, defPoly2, x0, x1): 173 | roots_0 = 10.0 174 | roots_1 = 10.0 175 | c = defPoly0 176 | b = defPoly1 177 | a = defPoly2 178 | delta = b*b - 4*a*c 179 | if delta > 0: 180 | d = ti.sqrt(delta) 181 | q = -0.5 * (b + d * NewSign(b)) 182 | rv0 = q / a 183 | rv1 = c / q 184 | r0 = ti.min(rv0, rv1) 185 | r1 = ti.max(rv0, rv1) 186 | if (r0 >= x0) and (r0 <= x1): 187 | roots_0 = r0 188 | if (r1 >= x0) and (r1 <= x1): 189 | roots_1 = r1 190 | elif delta == 0: 191 | r0 = -0.5 * b / a 192 | if (r0 >= x0) and (r0 <= x1): 193 | roots_0 = r0 194 | return roots_0, roots_1 195 | 196 | @ti.func 197 | def PolynomialDeflate(coef, root): 198 | defPoly2 = coef[3] 199 | defPoly1 = coef[2] + root * defPoly2 200 | defPoly0 = coef[1] + root * defPoly1 201 | return defPoly0,defPoly1,defPoly2 202 | 203 | @ti.func 204 | def cubic_eval(coef, x): 205 | return x * (x * ( coef[3] * x + coef[2]) + coef[1]) + coef[0] 206 | 207 | @ti.func 208 | def NewSign(x): 209 | return ti.cast( (x >= 0) - (x<0) , ti.f32) 210 | # ( T v, S sign ) { return v * (sign<0 ? T(-1) : T(1)); } 211 | 212 | @ti.func 213 | def IsDifferentSign(a, b): 214 | return (a<0) != (b<0) 215 | 216 | @ti.func 217 | def FindClosed(coef, deriv, x0, x1, y0, xError): 218 | ep2 = 2 * xError 219 | xr = (x0 + x1) / 2 220 | ret = False 221 | if x1 - x0 > ep2: 222 | xr0 = xr 223 | for safetyCounter in range(16): 224 | xn = xr - cubic_eval(coef, xr) / cubic_eval(deriv, xr) 225 | xn = ti.max(x0, ti.min(x1, xn)) 226 | if abs(xr - xn) <= xError: 227 | ret = True 228 | xr = xn 229 | break 230 | # return xn 231 | xr = xn 232 | if ret == False: 233 | if not ti.math.isinf(xr): 234 | xr = xr0 235 | 236 | yr = cubic_eval(coef, xr) 237 | xb0 = x0 238 | xb1 = x1 239 | while True: 240 | side = IsDifferentSign(y0,yr) 241 | if side: 242 | xb1 = xr 243 | else: 244 | xb0 = xr 245 | dy = cubic_eval(deriv, xr) 246 | dx = yr / dy 247 | xn = xr - dx 248 | if (xn > xb0) and (xn < xb1): 249 | stepsize = ti.abs(xr - xn) 250 | xr = xn 251 | if stepsize > xError: 252 | yr = cubic_eval(coef, xr) 253 | else: 254 | break 255 | else: 256 | xr = (xb0 + xb1) / 2 257 | if (xr == xb0) or (xr == xb1) or (xb1 - xb0 <= ep2): 258 | break 259 | yr = cubic_eval(coef, xr) 260 | return xr 261 | 262 | @ti.kernel 263 | def print_cubic_roots(): 264 | x0 = 0.0 265 | x1 = 1.0 266 | coef = ti.Vector([-0.04, 0.53, -1.4, 1], ti.f32) 267 | # print(cubic_eval(coef, 0.1)) 268 | # print(cubic_eval(coef, 0.5)) 269 | # print(cubic_eval(coef, 0.8)) 270 | # roots = cubic_roots(coef, x0, x1, tol=1e-3) 271 | # print(roots) 272 | root = cubic_first_root(coef, x0, x1, tol=1e-3) 273 | # roots = test0() 274 | # print(root) 275 | 276 | @ti.func 277 | def test0(): 278 | roots = ti.Vector([1,2,3,4], ti.f32) 279 | roots = test1(roots) 280 | return roots 281 | 282 | @ti.func 283 | def test1(roots): 284 | roots[1] = -1 285 | if True: 286 | roots[3] = -2 287 | return roots 288 | 289 | 290 | if __name__ == '__main__': 291 | ti.init(ti.gpu, default_fp=ti.f32, kernel_profiler=True) 292 | print_cubic_roots() 293 | ti.profiler.clear_kernel_profiler_info() 294 | for i in range(100000): 295 | print_cubic_roots() 296 | ti.profiler.print_kernel_profiler_info() 297 | 298 | 299 | # template 300 | # inline ftype RootFinderNewton::FindClosed( ftype const coef[N+1], ftype const deriv[N], ftype x0, ftype x1, ftype y0, ftype y1, ftype xError ) 301 | # { 302 | # ftype ep2 = 2*xError; 303 | # ftype xr = (x0 + x1) / 2; // mid point 304 | # if ( x1-x0 <= ep2 ) return xr; 305 | # 306 | # if constexpr ( N <= 3 ) { 307 | # ftype xr0 = xr; 308 | # for ( int safetyCounter=0; safetyCounter<16; ++safetyCounter ) { 309 | # ftype xn = xr - PolynomialEval( coef, xr ) / PolynomialEval<2,ftype>( deriv, xr ); 310 | # xn = Clamp( xn, x0, x1 ); 311 | # if ( std::abs(xr - xn) <= xError ) return xn; 312 | # xr = xn; 313 | # } 314 | # if ( ! IsFinite(xr) ) xr = xr0; 315 | # } 316 | # 317 | # ftype yr = PolynomialEval( coef, xr ); 318 | # ftype xb0 = x0; 319 | # ftype xb1 = x1; 320 | # 321 | # while ( true ) { 322 | # int side = IsDifferentSign( y0, yr ); 323 | # if ( side ) xb1 = xr; else xb0 = xr; 324 | # ftype dy = PolynomialEval( deriv, xr ); 325 | # ftype dx = yr / dy; 326 | # ftype xn = xr - dx; 327 | # if ( xn > xb0 && xn < xb1 ) { // valid Newton step 328 | # ftype stepsize = std::abs(xr-xn); 329 | # xr = xn; 330 | # if ( stepsize > xError ) { 331 | # yr = PolynomialEval( coef, xr ); 332 | # } else { 333 | # if constexpr ( boundError ) { 334 | # ftype xs; 335 | # if ( xError == 0 ) { 336 | # xs = std::nextafter( side?xb1:xb0, side?xb0:xb1 ); 337 | # } else { 338 | # xs = xn - MultSign( xError, side-1 ); 339 | # if ( xs == xn ) xs = std::nextafter( side?xb1:xb0, side?xb0:xb1 ); 340 | # } 341 | # ftype ys = PolynomialEval( coef, xs ); 342 | # int s = IsDifferentSign( y0, ys ); 343 | # if ( side != s ) return xn; 344 | # xr = xs; 345 | # yr = ys; 346 | # } else break; 347 | # } 348 | # } else { // Newton step failed 349 | # xr = (xb0 + xb1) / 2; 350 | # if ( xr == xb0 || xr == xb1 || xb1 - xb0 <= ep2 ) { 351 | # if constexpr ( boundError ) { 352 | # if ( xError == 0 ) { 353 | # ftype xm = side ? xb0 : xb1; 354 | # ftype ym = PolynomialEval( coef, xm ); 355 | # if ( std::abs(ym) < std::abs(yr) ) xr = xm; 356 | # } 357 | # } 358 | # break; 359 | # } 360 | # yr = PolynomialEval( coef, xr ); 361 | # } 362 | # } 363 | # return xr; 364 | # } 365 | # template 366 | # inline int CubicRoots( ftype roots[3], ftype const coef[4], ftype x0, ftype x1, ftype xError ) 367 | # { 368 | # const ftype y0 = PolynomialEval<3,ftype>( coef, x0 ); 369 | # const ftype y1 = PolynomialEval<3,ftype>( coef, x1 ); 370 | # 371 | # const ftype a = coef[3]*3; 372 | # const ftype b_2 = coef[2]; 373 | # const ftype c = coef[1]; 374 | # 375 | # const ftype deriv[4] = { c, 2*b_2, a, 0 }; 376 | # 377 | # const ftype delta_4 = b_2*b_2 - a*c; 378 | # 379 | # if ( delta_4 > 0 ) { 380 | # const ftype d_2 = Sqrt( delta_4 ); 381 | # const ftype q = - ( b_2 + MultSign( d_2, b_2 ) ); 382 | # ftype rv0 = q / a; 383 | # ftype rv1 = c / q; 384 | # const ftype xa = Min( rv0, rv1 ); 385 | # const ftype xb = Max( rv0, rv1 ); 386 | # 387 | # if ( IsDifferentSign(y0,y1) ) { 388 | # if ( xa >= x1 || xb <= x0 || ( xa <= x0 && xb >= x1 ) ) { // first, last, or middle interval only 389 | # roots[0] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, x0, x1, y0, y1, xError ); 390 | # return 1; 391 | # } 392 | # } else { 393 | # if ( ( xa >= x1 || xb <= x0 ) || ( xa <= x0 && xb >= x1 ) ) return 0; 394 | # } 395 | # 396 | # int numRoots = 0; 397 | # if ( xa > x0 ) { 398 | # const ftype ya = PolynomialEval<3,ftype>( coef, xa ); 399 | # if ( IsDifferentSign(y0,ya) ) { 400 | # roots[0] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, x0, xa, y0, ya, xError ); // first interval 401 | # if constexpr ( !boundError ) { 402 | # if ( IsDifferentSign(ya,y1) || ( xb < x1 && IsDifferentSign( ya, PolynomialEval<3,ftype>(coef,xb) ) ) ) { 403 | # ftype defPoly[4]; 404 | # PolynomialDeflate<3>( defPoly, coef, roots[0] ); 405 | # return QuadraticRoots( roots+1, defPoly, xa, x1 ) + 1; 406 | # } else return 1; 407 | # } else numRoots++; 408 | # } 409 | # if ( xb < x1 ) { 410 | # const ftype yb = PolynomialEval<3,ftype>( coef, xb ); 411 | # if ( IsDifferentSign(ya,yb) ) { 412 | # roots[ !boundError ? 0 : numRoots++ ] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, xa, xb, ya, yb, xError ); 413 | # if constexpr ( !boundError ) { 414 | # if ( IsDifferentSign(yb,y1) ) { 415 | # ftype defPoly[4]; 416 | # PolynomialDeflate<3>( defPoly, coef, roots[0] ); 417 | # return QuadraticRoots( roots+1, defPoly, xb, x1 ) + 1; 418 | # } else return 1; 419 | # } 420 | # } 421 | # if ( IsDifferentSign(yb,y1) ) { 422 | # roots[ !boundError ? 0 : numRoots++ ] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, xb, x1, yb, y1, xError ); // last interval 423 | # if constexpr ( !boundError ) return 1; 424 | # } 425 | # } else { 426 | # if ( IsDifferentSign(ya,y1) ) { 427 | # roots[ !boundError ? 0 : numRoots++ ] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, xa, x1, ya, y1, xError ); 428 | # if ( !boundError ) return 1; 429 | # } 430 | # } 431 | # } else { 432 | # const ftype yb = PolynomialEval<3,ftype>( coef, xb ); 433 | # if ( IsDifferentSign(y0,yb) ) { 434 | # roots[0] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, x0, xb, y0, yb, xError ); 435 | # if constexpr ( !boundError ) { 436 | # if ( IsDifferentSign(yb,y1) ) { 437 | # ftype defPoly[4]; 438 | # PolynomialDeflate<3>( defPoly, coef, roots[0] ); 439 | # return QuadraticRoots( roots+1, defPoly, xb, x1 ) + 1; 440 | # } else return 1; 441 | # } 442 | # else numRoots++; 443 | # } 444 | # if ( IsDifferentSign(yb,y1) ) { 445 | # roots[ !boundError ? 0 : numRoots++ ] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, xb, x1, yb, y1, xError ); // last interval 446 | # if constexpr ( !boundError ) return 1; 447 | # } 448 | # } 449 | # return numRoots; 450 | # 451 | # } else { 452 | # if ( IsDifferentSign(y0,y1) ) { 453 | # roots[0] = RootFinder::template FindClosed<3,ftype,boundError>( coef, deriv, x0, x1, y0, y1, xError ); 454 | # return 1; 455 | # } 456 | # return 0; 457 | # } 458 | # } -------------------------------------------------------------------------------- /math_utils/elastic_util.py: -------------------------------------------------------------------------------- 1 | # The functions for elastic deformation 2 | # dPsidF : first derivative of Psi w.r.t F 3 | # d2PsidF2 : second derivative of Psi w.r.t F 4 | 5 | import taichi as ti 6 | from math_utils.matrix_util import * 7 | 8 | # ARAP 9 | @ti.func 10 | def compute_Psi_ARAP(F, mu, la): 11 | U, sig, V = ssvd(F) 12 | R = U @ (V.transpose()) 13 | Psi = mu * (F - R).norm_sqr() 14 | return Psi 15 | 16 | @ti.func 17 | def compute_dPsidF_ARAP(F, mu, la): 18 | U, sig, V = ssvd(F) 19 | R = U @ (V.transpose()) 20 | dPsidF_3x3 = 2.0 * mu * (F - R) 21 | return dPsidF_3x3 22 | 23 | @ti.func 24 | def compute_dPsidx_ARAP(F, B, mu, la): 25 | dPsidF = compute_dPsidF_ARAP(F, mu, la) # 3x3 26 | dPsidx = compute_dFdx_T_N(B, dPsidF) # 12x1 27 | return dPsidx 28 | 29 | @ti.func 30 | def compute_diag_d2Psidx2_ARAP(F, B, mu, la): 31 | U, sig, V = ssvd(F) 32 | s0 = sig[0, 0] 33 | s1 = sig[1, 1] 34 | s2 = sig[2, 2] 35 | lambda0 = 2.0 / (s1 + s2) 36 | lambda1 = 2.0 / (s0 + s2) 37 | lambda2 = 2.0 / (s0 + s1) 38 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 39 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 40 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 41 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 42 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 43 | W0 = compute_dFdx_T_N(B, Q0) ** 2 44 | W1 = compute_dFdx_T_N(B, Q1) ** 2 45 | W2 = compute_dFdx_T_N(B, Q2) ** 2 46 | diag_h4 = lambda0 * W0 + lambda1 * W1 + lambda2 * W2 47 | X = compute_diag_dFdx_T_dFdx(B) 48 | return mu * (2.0 * X - diag_h4) 49 | 50 | 51 | @ti.func 52 | def compute_pHp_ARAP(F, B, p, mu, la): 53 | dFdx_p = compute_dFdx_p(B, p) # 9x1 54 | ret0 = dFdx_p.norm_sqr() 55 | U, sig, V = ssvd(F) 56 | s0 = sig[0, 0] 57 | s1 = sig[1, 1] 58 | s2 = sig[2, 2] 59 | lambda0 = 2.0 / (s1 + s2) 60 | lambda1 = 2.0 / (s0 + s2) 61 | lambda2 = 2.0 / (s0 + s1) 62 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 63 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 64 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 65 | # remove 1/sqrt(2) here 66 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 67 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 68 | Q0_flatten = flatten_matrix(Q0) 69 | Q1_flatten = flatten_matrix(Q1) 70 | Q2_flatten = flatten_matrix(Q2) 71 | ret1 = lambda0 * (Q0_flatten.dot(dFdx_p)) ** 2 + lambda1 * (Q1_flatten.dot(dFdx_p)) ** 2 + lambda2 * ( 72 | Q2_flatten.dot(dFdx_p)) ** 2 73 | ret = mu * (2.0 * ret0 - ret1) 74 | return ret 75 | 76 | 77 | # ARAP filter 78 | @ti.func 79 | def compute_diag_d2Psidx2_ARAP_filter(F, B, mu, la): 80 | U, sig, V = ssvd(F) 81 | s0 = sig[0, 0] 82 | s1 = sig[1, 1] 83 | s2 = sig[2, 2] 84 | lambda0 = 2.0 / (s1 + s2) 85 | lambda1 = 2.0 / (s0 + s2) 86 | lambda2 = 2.0 / (s0 + s1) 87 | if s1 + s2 < 2.0: 88 | lambda0 = 1.0 89 | if s0 + s2 < 2.0: 90 | lambda1 = 1.0 91 | if s0 + s1 < 2.0: 92 | lambda0 = 1.0 93 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 94 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 95 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 96 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 97 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 98 | W0 = compute_dFdx_T_N(B, Q0) ** 2 99 | W1 = compute_dFdx_T_N(B, Q1) ** 2 100 | W2 = compute_dFdx_T_N(B, Q2) ** 2 101 | diag_h4 = lambda0 * W0 + lambda1 * W1 + lambda2 * W2 102 | X = compute_diag_dFdx_T_dFdx(B) 103 | return mu * (2.0 * X - diag_h4) 104 | 105 | 106 | @ti.func 107 | def compute_pHp_ARAP_filter(F, B, p, mu, la): 108 | dFdx_p = compute_dFdx_p(B, p) # 9x1 109 | ret0 = dFdx_p.norm_sqr() 110 | U, sig, V = ssvd(F) 111 | s0 = sig[0, 0] 112 | s1 = sig[1, 1] 113 | s2 = sig[2, 2] 114 | lambda0 = 2.0 / (s1 + s2) 115 | lambda1 = 2.0 / (s0 + s2) 116 | lambda2 = 2.0 / (s0 + s1) 117 | if s1 + s2 < 2.0: 118 | lambda0 = 1.0 119 | if s0 + s2 < 2.0: 120 | lambda1 = 1.0 121 | if s0 + s1 < 2.0: 122 | lambda0 = 1.0 123 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 124 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 125 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 126 | # remove 1/sqrt(2) here 127 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 128 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 129 | Q0_flatten = flatten_matrix(Q0) 130 | Q1_flatten = flatten_matrix(Q1) 131 | Q2_flatten = flatten_matrix(Q2) 132 | ret1 = lambda0 * (Q0_flatten.dot(dFdx_p)) ** 2 + lambda1 * (Q1_flatten.dot(dFdx_p)) ** 2 + lambda2 * ( 133 | Q2_flatten.dot(dFdx_p)) ** 2 134 | ret = mu * (2.0 * ret0 - ret1) 135 | return ret 136 | 137 | 138 | # FCR 139 | @ti.func 140 | def compute_Psi_FCR(F, mu, la): 141 | U, sig, V = ssvd(F) 142 | R = U @ (V.transpose()) 143 | J = F.determinant() 144 | Psi = mu * (F - R).norm_sqr() + 0.5 * la * (J - 1.0) ** 2 145 | return Psi 146 | 147 | 148 | @ti.func 149 | def compute_dPsidF_FCR(F, mu, la): 150 | U, sig, V = ssvd(F) 151 | R = U @ (V.transpose()) 152 | dPsidF_3x3_ARAP = 2.0 * mu * (F - R) 153 | J = F.determinant() 154 | dJdF = compute_dJdF_3x3(F) 155 | dPsidF_3x3 = dPsidF_3x3_ARAP + la * (J - 1) * dJdF 156 | return dPsidF_3x3 157 | 158 | 159 | @ti.func 160 | def compute_dPsidx_FCR(F, B, mu, la): 161 | dPsidF = compute_dPsidF_FCR(F, mu, la) # 3x3 162 | dPsidx = compute_dFdx_T_N(B, dPsidF) 163 | return dPsidx 164 | 165 | 166 | @ti.func 167 | def compute_diag_d2Psidx2_FCR(F, B, mu, la): 168 | U, sig, V = ssvd(F) 169 | s0 = sig[0, 0] 170 | s1 = sig[1, 1] 171 | s2 = sig[2, 2] 172 | lambda0 = 2.0 / (s1 + s2) 173 | lambda1 = 2.0 / (s0 + s2) 174 | lambda2 = 2.0 / (s0 + s1) 175 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 176 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 177 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 178 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 179 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 180 | W0 = compute_dFdx_T_N(B, Q0) ** 2 181 | W1 = compute_dFdx_T_N(B, Q1) ** 2 182 | W2 = compute_dFdx_T_N(B, Q2) ** 2 183 | diag_h4 = lambda0 * W0 + lambda1 * W1 + lambda2 * W2 184 | X = compute_diag_dFdx_T_dFdx(B) 185 | diag_ARAP = mu * (2.0 * X - diag_h4) 186 | g3 = compute_dJdF_3x3(F) # g3 = dJdF 187 | dFdx_T_g3 = compute_dFdx_T_N(B, g3) 188 | diagJ = la * dFdx_T_g3 ** 2 189 | return diag_ARAP + diagJ 190 | 191 | 192 | @ti.func 193 | def compute_diag_d2Psidx2_FCR_filter(F, B, mu, la): 194 | U, sig, V = ssvd(F) 195 | s0 = sig[0, 0] 196 | s1 = sig[1, 1] 197 | s2 = sig[2, 2] 198 | lambda0 = 2.0 / (s1 + s2) 199 | lambda1 = 2.0 / (s0 + s2) 200 | lambda2 = 2.0 / (s0 + s1) 201 | if s1 + s2 < 2.0: 202 | lambda0 = 1.0 203 | if s0 + s2 < 2.0: 204 | lambda1 = 1.0 205 | if s0 + s1 < 2.0: 206 | lambda0 = 1.0 207 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 208 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 209 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 210 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 211 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 212 | W0 = compute_dFdx_T_N(B, Q0) ** 2 213 | W1 = compute_dFdx_T_N(B, Q1) ** 2 214 | W2 = compute_dFdx_T_N(B, Q2) ** 2 215 | diag_h4 = lambda0 * W0 + lambda1 * W1 + lambda2 * W2 216 | X = compute_diag_dFdx_T_dFdx(B) 217 | diag_ARAP = mu * (2.0 * X - diag_h4) 218 | g3 = compute_dJdF_3x3(F) # g3 = dJdF 219 | dFdx_T_g3 = compute_dFdx_T_N(B, g3) 220 | diagJ = la * dFdx_T_g3 ** 2 221 | return diag_ARAP + diagJ 222 | 223 | 224 | @ti.func 225 | def compute_pHp_FCR(F, B, p, mu, la): 226 | dFdx_p = compute_dFdx_p(B, p) # 9x1 227 | ret0 = dFdx_p.norm_sqr() 228 | U, sig, V = ssvd(F) 229 | s0 = sig[0, 0] 230 | s1 = sig[1, 1] 231 | s2 = sig[2, 2] 232 | lambda0 = 2.0 / (s1 + s2) 233 | lambda1 = 2.0 / (s0 + s2) 234 | lambda2 = 2.0 / (s0 + s1) 235 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 236 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 237 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 238 | # remove 1/sqrt(2) here 239 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 240 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 241 | Q0_flatten = flatten_matrix(Q0) 242 | Q1_flatten = flatten_matrix(Q1) 243 | Q2_flatten = flatten_matrix(Q2) 244 | ret1 = lambda0 * (Q0_flatten.dot(dFdx_p)) ** 2 + lambda1 * (Q1_flatten.dot(dFdx_p)) ** 2 + lambda2 * ( 245 | Q2_flatten.dot(dFdx_p)) ** 2 246 | ret_ARAP = mu * (2.0 * ret0 - ret1) 247 | g_3 = compute_vec_dJdF(F) 248 | ret_2 = la * ((g_3.dot(dFdx_p)) ** 2) 249 | J = F.determinant() 250 | ret_3 = la * (J - 1.0) * compute_d_H3_d(F, dFdx_p) 251 | return ret_ARAP + ret_2 + ret_3 252 | 253 | 254 | @ti.func 255 | def compute_pHp_FCR_filter(F, B, p, mu, la): 256 | dFdx_p = compute_dFdx_p(B, p) # 9x1 257 | ret0 = dFdx_p.norm_sqr() 258 | U, sig, V = ssvd(F) 259 | s0 = sig[0, 0] 260 | s1 = sig[1, 1] 261 | s2 = sig[2, 2] 262 | lambda0 = 2.0 / (s1 + s2) 263 | lambda1 = 2.0 / (s0 + s2) 264 | lambda2 = 2.0 / (s0 + s1) 265 | if s1 + s2 < 2.0: 266 | lambda0 = 1.0 267 | if s0 + s2 < 2.0: 268 | lambda1 = 1.0 269 | if s0 + s1 < 2.0: 270 | lambda0 = 1.0 271 | U0, U1, U2 = U[:, 0], U[:, 1], U[:, 2] 272 | V0, V1, V2 = V[:, 0], V[:, 1], V[:, 2] 273 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 274 | # remove 1/sqrt(2) here 275 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 276 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 277 | Q0_flatten = flatten_matrix(Q0) 278 | Q1_flatten = flatten_matrix(Q1) 279 | Q2_flatten = flatten_matrix(Q2) 280 | ret1 = lambda0 * (Q0_flatten.dot(dFdx_p)) ** 2 + lambda1 * (Q1_flatten.dot(dFdx_p)) ** 2 + lambda2 * ( 281 | Q2_flatten.dot(dFdx_p)) ** 2 282 | ret_ARAP = mu * (2.0 * ret0 - ret1) 283 | g_3 = compute_vec_dJdF(F) 284 | ret_2 = la * ((g_3.dot(dFdx_p)) ** 2) 285 | J = F.determinant() 286 | ret_3 = la * (J - 1.0) * compute_d_H3_d(F, dFdx_p) 287 | if ret_3 < 0.0: 288 | ret_3 = 0.0 289 | return ret_ARAP + ret_2 + ret_3 290 | 291 | 292 | # SNH 293 | @ti.func 294 | def compute_Psi_SNH(F, mu, la): 295 | J = F.determinant() 296 | return 0.5 * mu * (F.norm_sqr() - 3) - mu * (J - 1) + 0.5 * la * (J - 1) ** 2 297 | 298 | 299 | @ti.func 300 | def compute_dPsidF_SNH(F, mu, la): 301 | # return 3x3 302 | J = F.determinant() 303 | dJdF = compute_dJdF_3x3(F) 304 | dPsidF = mu * F + (- mu + la * (J - 1)) * dJdF 305 | return dPsidF 306 | 307 | 308 | @ti.func 309 | def compute_dPsidx_SNH(F, B, mu, la): 310 | dPsidF = compute_dPsidF_SNH(F, mu, la) # 3x3 311 | dPsidx = compute_dFdx_T_N(B, dPsidF) # 12x1 312 | return dPsidx 313 | 314 | 315 | @ti.func 316 | def compute_diag_d2Psidx2_SNH(F, B, mu, la): 317 | g3 = compute_dJdF_3x3(F) # g3 = dJdF 318 | dFdx_T_g3 = compute_dFdx_T_N(B, g3) 319 | diag1 = la * dFdx_T_g3 ** 2 320 | diag2 = mu * compute_diag_dFdx_T_dFdx(B) 321 | return diag1 + diag2 322 | 323 | 324 | @ti.func 325 | def compute_pHp_SNH(F, B, p, mu, la): 326 | dFdx_p = compute_dFdx_p(B, p) # 9x1 327 | ret0 = mu * dFdx_p.norm_sqr() 328 | g_3 = compute_vec_dJdF(F) 329 | ret1 = la * ((g_3.dot(dFdx_p)) ** 2) 330 | J = F.determinant() 331 | ret2 = (la * (J - 1.0) - mu) * compute_d_H3_d(F, dFdx_p) 332 | return ret0 + ret1 + ret2 333 | 334 | @ti.func 335 | def compute_Psi_NH(F, mu, la): 336 | J = F.determinant() 337 | return 0.5 * mu * (F.norm_sqr() - 3) - mu * ti.log(J) + 0.5 * la * ti.log(J) ** 2 338 | 339 | 340 | @ti.func 341 | def compute_dPsidF_NH(F, mu, la): 342 | # return 3x3 343 | J = F.determinant() 344 | dJdF = compute_dJdF_3x3(F) 345 | para = (- mu + la * ti.log(J)) / J 346 | dPsidF = mu * F + para * dJdF 347 | return dPsidF.transpose() 348 | 349 | 350 | @ti.func 351 | def compute_dPsidx_NH(F, B, mu, la): 352 | dPsidF = compute_dPsidF_SNH(F, mu, la) # 3x3 353 | dPsidx = compute_dFdx_T_N(B, dPsidF) # 12x1 354 | return dPsidx 355 | 356 | 357 | @ti.func 358 | def compute_diag_d2Psidx2_NH(F, B, mu, la): 359 | J = F.determinant() 360 | g3 = compute_dJdF_3x3(F) # g3 = dJdF 361 | dFdx_T_g3 = compute_dFdx_T_N(B, g3) 362 | para = (la * (1.0 - ti.log(J)) + mu) / (J * J) 363 | diag1 = para * dFdx_T_g3 ** 2 364 | diag2 = mu * compute_diag_dFdx_T_dFdx(B) 365 | return diag1 + diag2 366 | 367 | 368 | @ti.func 369 | def compute_pHp_NH(F, B, p, mu, la): 370 | dFdx_p = compute_dFdx_p(B, p) # 9x1 371 | ret0 = mu * dFdx_p.norm_sqr() 372 | g_3 = compute_vec_dJdF(F) 373 | J = F.determinant() 374 | para1 = (la * (1.0 - ti.log(J)) + mu) / (J * J) 375 | ret1 = para1 * ((g_3.dot(dFdx_p)) ** 2) 376 | para2 = (la * ti.log(J) - mu) / J 377 | ret2 = para2 * compute_d_H3_d(F, dFdx_p) 378 | return ret0 + ret1 + ret2 379 | 380 | 381 | @ti.func 382 | def compute_d2PsidF2_ARAP(F, mu, la): 383 | U,sig,V = ssvd(F) 384 | s0 = sig[0,0] 385 | s1 = sig[1,1] 386 | s2 = sig[2,2] 387 | lambda0 = 2.0 / (s1 + s2) 388 | lambda1 = 2.0 / (s0 + s2) 389 | lambda2 = 2.0 / (s0 + s1) 390 | U0 = U[:, 0] 391 | U1 = U[:, 1] 392 | U2 = U[:, 2] 393 | V0 = V[:, 0] 394 | V1 = V[:, 1] 395 | V2 = V[:, 2] 396 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 397 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 398 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 399 | q0 = flatten_matrix(Q0) 400 | # remove 1/sqrt(2) here 401 | q1 = flatten_matrix(Q1) 402 | q2 = flatten_matrix(Q2) 403 | 404 | d2PsidF2 = - mu *( lambda0 * (q0.outer_product(q0)) + lambda1 * (q1.outer_product(q1)) + lambda2 * (q2.outer_product(q2)) ) 405 | # remove 2.0 here 406 | for i in ti.static(range(9)): 407 | d2PsidF2[i,i] += 2 * mu 408 | return d2PsidF2 409 | 410 | @ti.func 411 | def compute_d2PsidF2_ARAP_filter(F, mu, la): 412 | U,sig,V = ssvd(F) 413 | s0 = sig[0,0] 414 | s1 = sig[1,1] 415 | s2 = sig[2,2] 416 | lambda0 = 2.0 / (s1 + s2) 417 | lambda1 = 2.0 / (s0 + s2) 418 | lambda2 = 2.0 / (s0 + s1) 419 | if s1 + s2 < 2.0: 420 | lambda0 = 1.0 421 | if s0 + s2 < 2.0: 422 | lambda1 = 1.0 423 | if s0 + s1 < 2.0: 424 | lambda0 = 1.0 425 | 426 | U0 = U[:, 0] 427 | U1 = U[:, 1] 428 | U2 = U[:, 2] 429 | V0 = V[:, 0] 430 | V1 = V[:, 1] 431 | V2 = V[:, 2] 432 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 433 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 434 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 435 | q0 = flatten_matrix(Q0) 436 | # remove 1/sqrt(2) here 437 | q1 = flatten_matrix(Q1) 438 | q2 = flatten_matrix(Q2) 439 | 440 | d2PsidF2 = - mu * ( lambda0 * (q0.outer_product(q0)) + lambda1 * (q1.outer_product(q1)) + lambda2 * (q2.outer_product(q2)) ) 441 | # remove 2.0 here 442 | for i in ti.static(range(9)): 443 | d2PsidF2[i,i] += 2.0 * mu 444 | return d2PsidF2 445 | 446 | @ti.func 447 | def compute_d2PsidF2_SNH(F, mu, la): 448 | g3 = compute_vec_dJdF(F) 449 | H3 = compute_H3(F) 450 | J = F.determinant() 451 | ret = mu * g3.outer_product(g3) + (la * (J - 1.0) - mu) * H3 452 | for i in range(9): 453 | ret[i,i] += mu 454 | return ret 455 | 456 | @ti.func 457 | def compute_d2PsidF2_NH(F, mu, la): 458 | g3 = compute_vec_dJdF(F) 459 | H3 = compute_H3(F) 460 | J = F.determinant() 461 | para1 = (la * (1.0 - ti.log(J)) + mu) / (J * J) 462 | para2 = (la * ti.log(J) - mu) / J 463 | ret = para1 * g3.outer_product(g3) + para2 * H3 464 | for i in range(9): 465 | ret += mu 466 | return ret 467 | 468 | @ti.func 469 | def compute_d2PsidF2_FCR(F, mu, la): 470 | U,sig,V = ssvd(F) 471 | s0 = sig[0,0] 472 | s1 = sig[1,1] 473 | s2 = sig[2,2] 474 | lambda0 = 2.0 / (s1 + s2) 475 | lambda1 = 2.0 / (s0 + s2) 476 | lambda2 = 2.0 / (s0 + s1) 477 | U0 = U[:, 0] 478 | U1 = U[:, 1] 479 | U2 = U[:, 2] 480 | V0 = V[:, 0] 481 | V1 = V[:, 1] 482 | V2 = V[:, 2] 483 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 484 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 485 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 486 | q0 = flatten_matrix(Q0) 487 | q1 = flatten_matrix(Q1) 488 | q2 = flatten_matrix(Q2) 489 | 490 | # ARAP 491 | d2PsidF2_ARAP = - mu *( lambda0 * (q0.outer_product(q0)) + lambda1 * (q1.outer_product(q1)) + lambda2 * (q2.outer_product(q2)) ) 492 | for i in ti.static(range(9)): 493 | d2PsidF2_ARAP[i,i] += 2 * mu 494 | 495 | g3 = compute_vec_dJdF(F) 496 | H3 = compute_H3(F) 497 | J = F.determinant() 498 | d2PsidF2_FCR = d2PsidF2_ARAP + la * g3.outer_product(g3) + la * (J-1) * H3 499 | return d2PsidF2_FCR 500 | 501 | 502 | @ti.func 503 | def compute_d2PsidF2_FCR_filter(F, mu, la): 504 | U, sig, V = ssvd(F) 505 | s0 = sig[0, 0] 506 | s1 = sig[1, 1] 507 | s2 = sig[2, 2] 508 | lambda0 = 2.0 / (s1 + s2) 509 | lambda1 = 2.0 / (s0 + s2) 510 | lambda2 = 2.0 / (s0 + s1) 511 | if s1 + s2 < 2.0: 512 | lambda0 = 1.0 513 | if s0 + s2 < 2.0: 514 | lambda1 = 1.0 515 | if s0 + s1 < 2.0: 516 | lambda0 = 1.0 517 | U0 = U[:, 0] 518 | U1 = U[:, 1] 519 | U2 = U[:, 2] 520 | V0 = V[:, 0] 521 | V1 = V[:, 1] 522 | V2 = V[:, 2] 523 | Q0 = V1.outer_product(U2) - V2.outer_product(U1) 524 | Q1 = V2.outer_product(U0) - V0.outer_product(U2) 525 | Q2 = V1.outer_product(U0) - V0.outer_product(U1) 526 | q0 = flatten_matrix(Q0) 527 | q1 = flatten_matrix(Q1) 528 | q2 = flatten_matrix(Q2) 529 | 530 | # ARAP 531 | d2PsidF2_ARAP = - mu * ( 532 | lambda0 * (q0.outer_product(q0)) + lambda1 * (q1.outer_product(q1)) + lambda2 * (q2.outer_product(q2))) 533 | for i in ti.static(range(9)): 534 | d2PsidF2_ARAP[i, i] += 2 * mu 535 | 536 | g3 = compute_vec_dJdF(F) 537 | H3 = compute_H3(F) 538 | J = F.determinant() 539 | d2PsidF2_FCR = d2PsidF2_ARAP + la * g3.outer_product(g3) + la * (J - 1) * H3 540 | return d2PsidF2_FCR 541 | -------------------------------------------------------------------------------- /math_utils/graphic_util.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | @ti.func 3 | def dist3D_Segment_to_Segment(A0,A1,B0,B1): 4 | u = A1 - A0 5 | v = B1 - B0 6 | w = A0 - B0 7 | a = u.norm_sqr() 8 | b = u.dot(v) 9 | c = v.norm_sqr() 10 | d = u.dot(w) 11 | e = v.dot(w) 12 | D = a * c - b * b 13 | sc, sN, sD = D, D, D 14 | tc, tN, tD = D, D, D 15 | if D < 1e-7: 16 | sN = 0.0 17 | sD = 1.0 18 | tN = e 19 | tD = c 20 | else: 21 | sN = b * e - c * d 22 | tN = a * e - b * d 23 | if sN < 0.0: 24 | sN = 0.0 25 | tN = e 26 | tD = c 27 | elif sN > sD: 28 | sN = sD 29 | tN = e + b 30 | tD = c 31 | if tN < 0.0: 32 | tN = 0.0 33 | if -d < 0.0: 34 | sN = 0.0 35 | elif -d > a: 36 | sN = sD 37 | else: 38 | sN = -d 39 | sD = a 40 | elif tN > tD: 41 | tN = tD 42 | if -d + b < 0.0: 43 | sN = 0.0 44 | elif -d + b > a: 45 | sN = sD 46 | else: 47 | sN = -d + b 48 | sD = a 49 | 50 | if ti.abs(sN) < 1e-7: 51 | sc = 0.0 52 | else: 53 | sc = sN / sD 54 | if ti.abs(tN) < 1e-7: 55 | tc = 0.0 56 | else: 57 | tc = tN / tD 58 | dP = - w - (sc * u) + (tc * v) # Qc - Pc 59 | return dP, sc, tc 60 | 61 | @ti.func 62 | def dist3D_Point_Triangle(P, V0, V1, V2): 63 | cord0 = 0.0 64 | cord1 = 0.0 65 | cord2 = 0.0 66 | v = V2 - V0 67 | u = V1 - V0 68 | nVec = u.cross(v) 69 | s_p = (nVec.dot(P - V0)) / (nVec.dot(nVec)) 70 | P0 = P - s_p * nVec # P project to plane 71 | w = P0 - V0 72 | n_cross_v = nVec.cross(v) 73 | n_cross_u = nVec.cross(u) 74 | s = w.dot(n_cross_v) / (u.dot(n_cross_v)) 75 | t = w.dot(n_cross_u) / (v.dot(n_cross_u)) 76 | if s >= 0.0 and t >= 0.0: 77 | if s + t <= 1.0: 78 | cord0 = 1.0 - s - t 79 | cord1 = s 80 | cord2 = t 81 | else: 82 | q = V2 - V1 83 | k = (P - V1).dot(q) / (q.dot(q)) 84 | if k > 1.0: 85 | cord2 = 1.0 86 | elif k < 0.0: 87 | cord1 = 1.0 88 | else: 89 | cord1 = 1.0 - k 90 | cord2 = k 91 | elif s >= 0.0 and t < 0.0: 92 | k = w.dot(u) / (u.dot(u)) 93 | if k > 1.0: 94 | cord1 = 1.0 95 | elif k < 0.0: 96 | cord0 = 1.0 97 | else: 98 | cord0 = 1.0 - k 99 | cord1 = k 100 | elif s < 0.0 and t >= 0.0: 101 | k = w.dot(v) / (v.dot(v)) 102 | if k > 1.0: 103 | cord2 = 1.0 104 | elif k < 0.0: 105 | cord0 = 1.0 106 | else: 107 | cord0 = 1.0 - k 108 | cord2 = k 109 | else: # s < 0 and t < 0 110 | cord0 = 1.0 111 | return cord0, cord1, cord2 112 | 113 | 114 | @ti.func 115 | def dist3D_Point_Triangle_type(P, V0, V1, V2): 116 | cord0 = 0.0 117 | cord1 = 0.0 118 | cord2 = 0.0 119 | v = V2 - V0 120 | u = V1 - V0 121 | nVec = u.cross(v) 122 | s_p = (nVec.dot(P - V0)) / (nVec.dot(nVec)) 123 | P0 = P - s_p * nVec # P project to plane 124 | w = P0 - V0 125 | n_cross_v = nVec.cross(v) 126 | n_cross_u = nVec.cross(u) 127 | s = w.dot(n_cross_v) / (u.dot(n_cross_v)) 128 | t = w.dot(n_cross_u) / (v.dot(n_cross_u)) 129 | type = 0 # 0: PP, 1: PE, 2: PT 130 | if s >= 0.0 and t >= 0.0: 131 | if s + t <= 1.0: 132 | cord0 = 1.0 - s - t 133 | cord1 = s 134 | cord2 = t 135 | type = 2 136 | else: 137 | q = V2 - V1 138 | k = (P - V1).dot(q) / (q.dot(q)) 139 | if k > 1.0: 140 | cord2 = 1.0 141 | type = 0 142 | elif k < 0.0: 143 | cord1 = 1.0 144 | type = 0 145 | else: 146 | cord1 = 1.0 - k 147 | cord2 = k 148 | type = 1 149 | elif s >= 0.0 and t < 0.0: 150 | k = w.dot(u) / (u.dot(u)) 151 | if k > 1.0: 152 | cord1 = 1.0 153 | type = 0 154 | elif k < 0.0: 155 | cord0 = 1.0 156 | type = 0 157 | else: 158 | cord0 = 1.0 - k 159 | cord1 = k 160 | type = 1 161 | elif s < 0.0 and t >= 0.0: 162 | k = w.dot(v) / (v.dot(v)) 163 | if k > 1.0: 164 | cord2 = 1.0 165 | type = 0 166 | elif k < 0.0: 167 | cord0 = 1.0 168 | type = 0 169 | else: 170 | cord0 = 1.0 - k 171 | cord2 = k 172 | type = 1 173 | else: # s < 0 and t < 0 174 | cord0 = 1.0 175 | type = 0 176 | return cord0, cord1, cord2, type 177 | 178 | 179 | @ti.func 180 | def dcd_line_triangle(xa, xb, x0, x1, x2): 181 | ret = 0 182 | x10 = x1 - x0 183 | x20 = x2 - x0 184 | N = x10.cross(x20) 185 | x0a = x0 - xa 186 | xba = xb - xa 187 | t = x0a.dot(N) / xba.dot(N) 188 | if t >= 0.0 and t <= 1.0: 189 | xt = (1-t) * x0 + t * x1 190 | ret0 = ((x0 - xt).cross(x1-xt)).dot(N) 191 | ret1 = ((x1 - xt).cross(x2-xt)).dot(N) 192 | ret2 = ((x2 - xt).cross(x0-xt)).dot(N) 193 | if ret0 >= 0 and ret1 >= 0 and ret2 >= 0: 194 | ret = 1 195 | return ret 196 | 197 | @ti.func 198 | def segment_intersect_triangle_new(P0, P1, V0, V1, V2): 199 | ret = 0 200 | u = V1 - V0 201 | v = V2 - V0 202 | n = u.cross(v) 203 | if n.norm() > 1e-6: # triangle is not degenerate 204 | dir = P1 - P0 205 | w0 = P0 - V0 206 | a = - n.dot(w0) 207 | b = n.dot(dir) 208 | if ti.abs(b) > 1e-6: #ray is not parallel to triangle plane 209 | r = a / b 210 | if r >= 0.0 and r <= 1.0: 211 | I = P0 + r * dir # intersection point 212 | uu = u.dot(u) 213 | uv = u.dot(v) 214 | vv = v.dot(v) 215 | w = I - V0 216 | wu = w.dot(u) 217 | wv = w.dot(v) 218 | D = uv * uv - uu * vv 219 | s = (uv * wv - vv * wu) / D 220 | t = (uv * wu - uu * wv) / D 221 | if s< 0.0 or s > 1.0: 222 | ret = 0 223 | elif t < 0.0 or (s+t) > 1.0: 224 | ret = 0 225 | else: 226 | ret = 1 227 | return ret 228 | 229 | 230 | 231 | 232 | 233 | @ti.func 234 | def segment_intersect_triangle(P, Q, A, B, C): 235 | RLen = (Q - P).norm() 236 | RDir = (Q - P) / RLen 237 | ROrigin = P 238 | E1 = B - A 239 | E2 = C - A 240 | N = E1.cross(E2) 241 | det = -RDir.dot(N) 242 | invdet = 1.0 / det 243 | AO = ROrigin - A 244 | DAO = AO.cross(RDir) 245 | u = E2.dot(DAO) * invdet 246 | v = -E1.dot(DAO) * invdet 247 | t = AO.dot(N) * invdet 248 | ret = 0 249 | if det >= 1e-5 and t >= 1e-6 and u >= 1e-6 and v >= 1e-6 and (u+v) <= 1.0-1e-6 and t <= RLen: 250 | ret = 1 251 | # print(det,det>=1e-5, t, t>=0.0, u, u>=0.0, v, v>=0.0, (u+v) <= 1.0, t <= RLen) 252 | 253 | return ret 254 | # return det >= 1e-12 and t >= 0.0 and u >= 0.0 and v >= 0.0 and (u+v) <= 1.0 and t <= RLen 255 | 256 | @ti.func 257 | def point_triangle_ccd_broadphase(p0, t0, t1, t2, dHat): 258 | min_t = ti.min(ti.min(t0, t1), t2) 259 | max_t = ti.max(ti.max(t0, t1), t2) 260 | return (p0 < max_t + dHat).all() and (min_t - dHat < p0).all() 261 | 262 | @ti.func 263 | def edge_edge_ccd_broadphase(a0, a1, b0, b1, dHat): 264 | max_a = ti.max(a0, a1) 265 | min_a = ti.min(a0, a1) 266 | max_b = ti.max(b0, b1) 267 | min_b = ti.min(b0, b1) 268 | return (min_a < max_b + dHat).all() and (min_b - dHat < max_a).all() -------------------------------------------------------------------------------- /math_utils/matrix_util.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | @ti.func 3 | def ssvd(F): 4 | U, sig, V = ti.svd(F) 5 | if U.determinant() < 0: 6 | for i in ti.static(range(3)): 7 | U[i, 2] *= -1 8 | sig[2, 2] = -sig[2, 2] 9 | if V.determinant() < 0: 10 | for i in ti.static(range(3)): 11 | V[i, 2] *= -1 12 | sig[2, 2] = -sig[2, 2] 13 | return U, sig, V 14 | 15 | @ti.func 16 | def compute_dFdx_T_N(B, N): 17 | # vec(dFdx)^T vec(N) , N:3x3(before vec), B 3x3 -> 12x1 18 | B00, B01, B02, B10, B11, B12, B20, B21, B22 = B[0,0], B[0,1], B[0,2], B[1,0], B[1,1], B[1,2], B[2,0], B[2,1], B[2,2] 19 | N00, N01, N02, N10, N11, N12, N20, N21, N22 = N[0,0], N[0,1], N[0,2], N[1,0], N[1,1], N[1,2], N[2,0], N[2,1], N[2,2] 20 | r3 = B00 * N00 + B01 * N01 + B02 * N02 21 | r4 = B00 * N10 + B01 * N11 + B02 * N12 22 | r5 = B00 * N20 + B01 * N21 + B02 * N22 23 | r6 = B10 * N00 + B11 * N01 + B12 * N02 24 | r7 = B10 * N10 + B11 * N11 + B12 * N12 25 | r8 = B10 * N20 + B11 * N21 + B12 * N22 26 | r9 = B20 * N00 + B21 * N01 + B22 * N02 27 | r10 = B20 * N10 + B21 * N11 + B22 * N12 28 | r11 = B20 * N20 + B21 * N21 + B22 * N22 29 | r0 = -r3 - r6 - r9 30 | r1 = -r4 - r7 - r10 31 | r2 = -r5 - r8 - r11 32 | return ti.Matrix([r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11],float) 33 | 34 | @ti.func 35 | def compute_dFdxT_p(B, p): 36 | # dFdx transpose 12x9, p 9x1 -> 12x1 37 | B00, B01, B02, B10, B11, B12, B20, B21, B22 = B[0, 0], B[0, 1], B[0, 2], B[1, 0], B[1, 1], B[1, 2], B[2, 0], B[2, 1], B[2, 2] 38 | p0, p1, p2, p3, p4, p5, p6, p7, p8 = p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8] 39 | r3 = B00 * p0 + B01 * p3 + B02 * p6 40 | r4 = B00 * p1 + B01 * p4 + B02 * p7 41 | r5 = B00 * p2 + B01 * p5 + B02 * p8 42 | r6 = B10 * p0 + B11 * p3 + B12 * p6 43 | r7 = B10 * p1 + B11 * p4 + B12 * p7 44 | r8 = B10 * p2 + B11 * p5 + B12 * p8 45 | r9 = B20 * p0 + B21 * p3 + B22 * p6 46 | r10 = B20 * p1 + B21 * p4 + B22 * p7 47 | r11 = B20 * p2 + B21 * p5 + B22 * p8 48 | r0 = -(r3 + r6 + r9) 49 | r1 = -(r4 + r7 + r10) 50 | r2 = -(r5 + r8 + r11) 51 | return ti.Matrix([r0, r1, r2, 52 | r3, r4, r5, 53 | r6, r7, r8, 54 | r9, r10, r11], float) 55 | 56 | @ti.func 57 | def compute_dFdx_p(B, p): 58 | # dFdx 9x12, p 12x1 59 | B00, B01, B02, B10, B11, B12, B20, B21, B22 = B[0, 0], B[0, 1], B[0, 2], B[1, 0], B[1, 1], B[1, 2], B[2, 0], B[2, 1], B[2, 2] 60 | p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11 = p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11] 61 | t1 = - B00 - B10 - B20 62 | t2 = - B01 - B11 - B21 63 | t3 = - B02 - B12 - B22 64 | return ti.Matrix([B00*p3 + B10*p6 + B20*p9 + p0*t1, 65 | B00*p4 + B10*p7 + B20*p10 + p1*t1, 66 | B00*p5 + B10*p8 + B20*p11 + p2*t1, 67 | B01*p3 + B11*p6 + B21*p9 + p0*t2, 68 | B01*p4 + B11*p7 + B21*p10 + p1*t2, 69 | B01*p5 + B11*p8 + B21*p11 + p2*t2, 70 | B02*p3 + B12*p6 + B22*p9 + p0*t3, 71 | B02*p4 + B12*p7 + B22*p10 + p1*t3, 72 | B02*p5 + B12*p8 + B22*p11 + p2*t3],float) 73 | 74 | @ti.func 75 | def compute_diag_h4(la0,la1,la2, B, U, V): 76 | B00, B01, B02, B10, B11, B12, B20, B21, B22 = B[0,0], B[0,1], B[0,2], B[1,0], B[1,1], B[1,2], B[2,0], B[2,1], B[2,2] 77 | U00, U01, U02, U10, U11, U12, U20, U21, U22 = U[0,0], U[0,1], U[0,2], U[1,0], U[1,1], U[1,2], U[2,0], U[2,1], U[2,2] 78 | V00, V01, V02, V10, V11, V12, V20, V21, V22 = V[0,0], V[0,1], V[0,2], V[1,0], V[1,1], V[1,2], V[2,0], V[2,1], V[2,2] 79 | r0 = la0*((U00*V01 - U01*V00)*(B00 + B10 + B20) + (U00*V11 - U01*V10)*(B01 + B11 + B21) + (U00*V21 - U01*V20)*(B02 + B12 + B22))**2 + la1*((U01*V02 - U02*V01)*(B00 + B10 + B20) + (U01*V12 - U02*V11)*(B01 + B11 + B21) + (U01*V22 - U02*V21)*(B02 + B12 + B22))**2 + la2*((U00*V02 - U02*V00)*(B00 + B10 + B20) + (U00*V12 - U02*V10)*(B01 + B11 + B21) + (U00*V22 - U02*V20)*(B02 + B12 + B22))**2 80 | r1 = la0*((U10*V01 - U11*V00)*(B00 + B10 + B20) + (U10*V11 - U11*V10)*(B01 + B11 + B21) + (U10*V21 - U11*V20)*(B02 + B12 + B22))**2 + la1*((U11*V02 - U12*V01)*(B00 + B10 + B20) + (U11*V12 - U12*V11)*(B01 + B11 + B21) + (U11*V22 - U12*V21)*(B02 + B12 + B22))**2 + la2*((U10*V02 - U12*V00)*(B00 + B10 + B20) + (U10*V12 - U12*V10)*(B01 + B11 + B21) + (U10*V22 - U12*V20)*(B02 + B12 + B22))**2 81 | r2 = la0*((U20*V01 - U21*V00)*(B00 + B10 + B20) + (U20*V11 - U21*V10)*(B01 + B11 + B21) + (U20*V21 - U21*V20)*(B02 + B12 + B22))**2 + la1*((U21*V02 - U22*V01)*(B00 + B10 + B20) + (U21*V12 - U22*V11)*(B01 + B11 + B21) + (U21*V22 - U22*V21)*(B02 + B12 + B22))**2 + la2*((U20*V02 - U22*V00)*(B00 + B10 + B20) + (U20*V12 - U22*V10)*(B01 + B11 + B21) + (U20*V22 - U22*V20)*(B02 + B12 + B22))**2 82 | r3 = la0*(B00*(U00*V01 - U01*V00) + B01*(U00*V11 - U01*V10) + B02*(U00*V21 - U01*V20))**2 + la1*(B00*(U01*V02 - U02*V01) + B01*(U01*V12 - U02*V11) + B02*(U01*V22 - U02*V21))**2 + la2*(B00*(U00*V02 - U02*V00) + B01*(U00*V12 - U02*V10) + B02*(U00*V22 - U02*V20))**2 83 | r4 = la0*(B00*(U10*V01 - U11*V00) + B01*(U10*V11 - U11*V10) + B02*(U10*V21 - U11*V20))**2 + la1*(B00*(U11*V02 - U12*V01) + B01*(U11*V12 - U12*V11) + B02*(U11*V22 - U12*V21))**2 + la2*(B00*(U10*V02 - U12*V00) + B01*(U10*V12 - U12*V10) + B02*(U10*V22 - U12*V20))**2 84 | r5 = la0*(B00*(U20*V01 - U21*V00) + B01*(U20*V11 - U21*V10) + B02*(U20*V21 - U21*V20))**2 + la1*(B00*(U21*V02 - U22*V01) + B01*(U21*V12 - U22*V11) + B02*(U21*V22 - U22*V21))**2 + la2*(B00*(U20*V02 - U22*V00) + B01*(U20*V12 - U22*V10) + B02*(U20*V22 - U22*V20))**2 85 | r6 = la0*(B10*(U00*V01 - U01*V00) + B11*(U00*V11 - U01*V10) + B12*(U00*V21 - U01*V20))**2 + la1*(B10*(U01*V02 - U02*V01) + B11*(U01*V12 - U02*V11) + B12*(U01*V22 - U02*V21))**2 + la2*(B10*(U00*V02 - U02*V00) + B11*(U00*V12 - U02*V10) + B12*(U00*V22 - U02*V20))**2 86 | r7 = la0*(B10*(U10*V01 - U11*V00) + B11*(U10*V11 - U11*V10) + B12*(U10*V21 - U11*V20))**2 + la1*(B10*(U11*V02 - U12*V01) + B11*(U11*V12 - U12*V11) + B12*(U11*V22 - U12*V21))**2 + la2*(B10*(U10*V02 - U12*V00) + B11*(U10*V12 - U12*V10) + B12*(U10*V22 - U12*V20))**2 87 | r8 = la0*(B10*(U20*V01 - U21*V00) + B11*(U20*V11 - U21*V10) + B12*(U20*V21 - U21*V20))**2 + la1*(B10*(U21*V02 - U22*V01) + B11*(U21*V12 - U22*V11) + B12*(U21*V22 - U22*V21))**2 + la2*(B10*(U20*V02 - U22*V00) + B11*(U20*V12 - U22*V10) + B12*(U20*V22 - U22*V20))**2 88 | r9 = la0*(B20*(U00*V01 - U01*V00) + B21*(U00*V11 - U01*V10) + B22*(U00*V21 - U01*V20))**2 + la1*(B20*(U01*V02 - U02*V01) + B21*(U01*V12 - U02*V11) + B22*(U01*V22 - U02*V21))**2 + la2*(B20*(U00*V02 - U02*V00) + B21*(U00*V12 - U02*V10) + B22*(U00*V22 - U02*V20))**2 89 | r10 = la0*(B20*(U10*V01 - U11*V00) + B21*(U10*V11 - U11*V10) + B22*(U10*V21 - U11*V20))**2 + la1*(B20*(U11*V02 - U12*V01) + B21*(U11*V12 - U12*V11) + B22*(U11*V22 - U12*V21))**2 + la2*(B20*(U10*V02 - U12*V00) + B21*(U10*V12 - U12*V10) + B22*(U10*V22 - U12*V20))**2 90 | r11 = la0*(B20*(U20*V01 - U21*V00) + B21*(U20*V11 - U21*V10) + B22*(U20*V21 - U21*V20))**2 + la1*(B20*(U21*V02 - U22*V01) + B21*(U21*V12 - U22*V11) + B22*(U21*V22 - U22*V21))**2 + la2*(B20*(U20*V02 - U22*V00) + B21*(U20*V12 - U22*V10) + B22*(U20*V22 - U22*V20))**2 91 | return 0.5 * ti.Vector([r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11],float) 92 | 93 | @ti.func 94 | def compute_pT_h4_p(la0,la1,la2,U,V,d): 95 | #d = dFdx @ p 9x1 96 | U00, U01, U02, U10, U11, U12, U20, U21, U22 = U[0,0], U[0,1], U[0,2], U[1,0], U[1,1], U[1,2], U[2,0], U[2,1], U[2,2] 97 | V00, V01, V02, V10, V11, V12, V20, V21, V22 = V[0,0], V[0,1], V[0,2], V[1,0], V[1,1], V[1,2], V[2,0], V[2,1], V[2,2] 98 | d0, d1, d2, d3, d4, d5, d6, d7, d8 = d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8] 99 | return 0.5 * ( 100 | la0*( d0*(U00*V01 - U01*V00) + d1*(U10*V01 - U11*V00) + d2*(U20*V01 - U21*V00) + d3*(U00*V11 - U01*V10) + d4*(U10*V11 - U11*V10) + d5*(U20*V11 - U21*V10) + d6*(U00*V21 - U01*V20) + d7*(U10*V21 - U11*V20) + d8*(U20*V21 - U21*V20) )**2 + 101 | la1*(d0*(U01*V02 - U02*V01) + d1*(U11*V02 - U12*V01) + d2*(U21*V02 - U22*V01) + d3*(U01*V12 - U02*V11) + d4*(U11*V12 - U12*V11) + d5*(U21*V12 - U22*V11) + d6*(U01*V22 - U02*V21) + d7*(U11*V22 - U12*V21) + d8*(U21*V22 - U22*V21))**2 + 102 | la2*(d0*(U00*V02 - U02*V00) + d1*(U10*V02 - U12*V00) + d2*(U20*V02 - U22*V00) + d3*(U00*V12 - U02*V10) + d4*(U10*V12 - U12*V10) + d5*(U20*V12 - U22*V10) + d6*(U00*V22 - U02*V20) + d7*(U10*V22 - U12*V20) + d8*(U20*V22 - U22*V20))**2 103 | ) 104 | 105 | @ti.func 106 | def compute_diag_dFdx_T_dFdx(B): 107 | B00, B01, B02, B10, B11, B12, B20, B21, B22 = B[0,0], B[0,1], B[0,2], B[1,0], B[1,1], B[1,2], B[2,0], B[2,1], B[2,2] 108 | tmp0 = (B00 + B10 + B20)**2 + (B01 + B11 + B21)**2 + (B02 + B12 + B22)**2 109 | tmp1 = B00**2 + B01**2 + B02**2 110 | tmp2 = B10**2 + B11**2 + B12**2 111 | tmp3 = B20**2 + B21**2 + B22**2 112 | return ti.Vector([tmp0, tmp0, tmp0, tmp1, tmp1, tmp1, tmp2, tmp2, tmp2, tmp3, tmp3, tmp3], float) 113 | 114 | @ti.func 115 | def flatten_matrix(A): 116 | # flattern 3x3 A to 9x1 vector (column first) 117 | return ti.Vector([A[0,0], A[1,0], A[2,0], A[0,1], A[1,1],A[2,1],A[0,2],A[1,2],A[2,2]],float) 118 | 119 | @ti.func 120 | def compute_d_H3_d(F, d): 121 | # d: 9x1, H3 9x9 122 | d0, d1, d2, d3, d4, d5, d6, d7, d8= d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8] 123 | F00, F01, F02, F10, F11, F12, F20, F21, F22 = F[0, 0], F[0, 1], F[0, 2], F[1, 0], F[1, 1], F[1, 2], F[2, 0], F[2, 1], F[2, 2] 124 | return 2 * (F00 * d4 * d8 - F00 * d5 * d7 - F01 * d1 * d8 + F01 * d2 * d7 125 | + F02 * d1 * d5 - F02 * d2 * d4 - F10 * d3 * d8 + F10 * d5 * d6 126 | + F11 * d0 * d8 - F11 * d2 * d6 - F12 * d0 * d5 + F12 * d2 * d3 127 | + F20 * d3 * d7 - F20 * d4 * d6 - F21 * d0 * d7 + F21 * d1 * d6 128 | + F22 * d0 * d4 - F22 * d1 * d3) 129 | 130 | @ti.func 131 | def compute_dJdF_3x3(F): 132 | """F:3x3->dJdF:3x3(before vec)""" 133 | F00, F01, F02, F10, F11, F12, F20, F21, F22 = F[0, 0], F[0, 1], F[0, 2], F[1, 0], F[1, 1], F[1, 2], F[2, 0], F[2, 1], F[2, 2] 134 | return ti.Matrix([[F11 * F22 - F12 * F21, -F10 * F22 + F12 * F20, F10 * F21 - F11 * F20], 135 | [-F01 * F22 + F02 * F21, F00 * F22 - F02 * F20, -F00 * F21 + F01 * F20], 136 | [F01 * F12 - F02 * F11, -F00 * F12 + F02 * F10, F00 * F11 - F01 * F10]], float) 137 | 138 | @ti.func 139 | def compute_vec_dJdF(F): 140 | """F:3x3->dJdF:9x1(after vec)""" 141 | F00, F01, F02, F10, F11, F12, F20, F21, F22 = F[0, 0], F[0, 1], F[0, 2], F[1, 0], F[1, 1], F[1, 2], F[2, 0], F[2, 1], F[2, 2] 142 | return ti.Matrix([F11 * F22 - F12 * F21, -F01 * F22 + F02 * F21, F01 * F12 - F02 * F11, 143 | -F10 * F22 + F12 * F20, F00 * F22 - F02 * F20, -F00 * F12 + F02 * F10, 144 | F10 * F21 - F11 * F20, -F00 * F21 + F01 * F20, F00 * F11 - F01 * F10],float) 145 | 146 | @ti.func 147 | def compute_H3(F): 148 | """F:3x3->H3:9x9""" 149 | F00, F01, F02, F10, F11, F12, F20, F21, F22 = F[0, 0], F[0, 1], F[0, 2], F[1, 0], F[1, 1], F[1, 2], F[2, 0], F[2, 1], F[2, 2] 150 | return ti.Matrix([[0, 0, 0, 0, F22, -F12, 0, -F21, F11], 151 | [0, 0, 0, -F22, 0, F02, F21, 0, -F01], 152 | [0, 0, 0, F12, -F02, 0, -F11, F01, 0], 153 | [0, -F22, F12, 0, 0, 0, 0, F20, -F10], 154 | [F22, 0, -F02, 0, 0, 0, -F20, 0, F00], 155 | [-F12, F02, 0, 0, 0, 0, F10, -F00, 0], 156 | [0, F21, -F11, 0, -F20, F10, 0, 0, 0], 157 | [-F21, 0, F01, F20, 0, -F00, 0, 0, 0], 158 | [F11, -F01, 0, -F10, F00, 0, 0, 0, 0]],float) 159 | 160 | 161 | @ti.func 162 | def compute_dtdx_t(t, cord): 163 | t0 = t[0] 164 | t1 = t[1] 165 | t2 = t[2] 166 | c0 = cord[0] 167 | c1 = cord[1] 168 | c2 = cord[2] 169 | c3 = cord[3] 170 | return ti.Vector([c0 * t0, c0 * t1, c0 * t2, c1 * t0, c1 * t1, c1 * t2, c2 * t0, c2 * t1, c2 * t2, c3 * t0, c3 * t1, c3 * t2],float) 171 | 172 | @ti.func 173 | def compute_d_dtdx(d, cord): 174 | return cord[0] * d[0:3] + cord[1] * d[3:6] + cord[2] * d[6:9] + cord[3] * d[9:12] 175 | 176 | @ti.func 177 | def compute_dFdx(DmInv): 178 | dFdx = ti.Matrix.zero(float,9,12) 179 | m = DmInv[0,0] 180 | n = DmInv[0,1] 181 | o = DmInv[0,2] 182 | p = DmInv[1,0] 183 | q = DmInv[1,1] 184 | r = DmInv[1,2] 185 | s = DmInv[2,0] 186 | t = DmInv[2,1] 187 | u = DmInv[2,2] 188 | t1 = -m-p-s 189 | t2 = -n-q-t 190 | t3 = -o-r-u 191 | dFdx[0,0] = t1 192 | dFdx[0,3] = m 193 | dFdx[0,6] = p 194 | dFdx[0,9] = s 195 | 196 | dFdx[1,1] = t1 197 | dFdx[1,4] = m 198 | dFdx[1,7] = p 199 | dFdx[1,10] = s 200 | 201 | dFdx[2,2] = t1 202 | dFdx[2,5] = m 203 | dFdx[2,8] = p 204 | dFdx[2,11] = s 205 | 206 | dFdx[3,0] = t2 207 | dFdx[3,3] = n 208 | dFdx[3,6] = q 209 | dFdx[3,9] = t 210 | 211 | dFdx[4,1] = t2 212 | dFdx[4,4] = n 213 | dFdx[4,7] = q 214 | dFdx[4,10] = t 215 | 216 | dFdx[5,2] = t2 217 | dFdx[5,5] = n 218 | dFdx[5,8] = q 219 | dFdx[5,11] = t 220 | 221 | dFdx[6,0] = t3 222 | dFdx[6,3] = o 223 | dFdx[6,6] = r 224 | dFdx[6,9] = u 225 | 226 | dFdx[7,1] = t3 227 | dFdx[7,4] = o 228 | dFdx[7,7] = r 229 | dFdx[7,10] = u 230 | 231 | dFdx[8,2] = t3 232 | dFdx[8,5] = o 233 | dFdx[8,8] = r 234 | dFdx[8,11] = u 235 | return dFdx 236 | 237 | -------------------------------------------------------------------------------- /math_utils/matrix_util_tmp.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | 3 | @ti.func 4 | def spd_matrix(D): 5 | A = ti.cast(D,float) 6 | N = A.n 7 | maxRot = 5*(N**2) 8 | p = ti.Matrix.identity(float,A.n) 9 | Iter = 0 10 | while Iter < maxRot: 11 | # for i in range(maxRot): 12 | Iter += 1 13 | k=0;l=1 14 | max_value = 0.0 15 | for i in range(N - 1): 16 | for j in range(i+1,N): 17 | if ti.abs(A[i,j])>max_value: 18 | max_value = ti.abs(A[i,j]) 19 | k=i;l=j 20 | # print('max_value',max_value) 21 | if max_value < 1.0e-7: 22 | # print('iter', Iter) 23 | break 24 | ADiff = A[l,l] - A[k,k] 25 | temp = A[k, l] 26 | t = 0.0 27 | # if ti.abs(A[k,l]) < ti.abs(ADiff)*1.0e-36: 28 | # t = A[k,l] / ADiff 29 | # else: 30 | if ti.abs(temp) >= ti.abs(ADiff)*1.0e-36: 31 | phi = ADiff / (2.0 * temp) 32 | t = 1.0 / (ti.abs(phi) + ti.sqrt(1.0 + phi**2)) 33 | if phi < 0.0: 34 | t = -t 35 | c = 1.0 / ti.sqrt(t ** 2 + 1.0); 36 | s = t * c 37 | tau = s / (1.0 + c) 38 | A[k, l] = 0.0 39 | A[k, k] = A[k, k] - t * temp 40 | A[l, l] = A[l, l] + t * temp 41 | for i in range(k): # Case of i < k 42 | temp = A[i, k] 43 | A[i, k] = temp - s * (A[i, l] + tau * temp) 44 | A[i, l] = A[i, l] + s * (temp - tau * A[i, l]) 45 | for i in range(k + 1, l): # Case of k < i < l 46 | temp = A[k, i] 47 | A[k, i] = temp - s * (A[i, l] + tau * A[k, i]) 48 | A[i, l] = A[i, l] + s * (temp - tau * A[i, l]) 49 | for i in range(l + 1, N): # Case of i > l 50 | temp = A[k, i] 51 | A[k, i] = temp - s * (A[l, i] + tau * temp) 52 | A[l, i] = A[l, i] + s * (temp - tau * A[l, i]) 53 | for i in range(N): # Update transformation matrix 54 | temp = p[i, k] 55 | p[i, k] = temp - s * (p[i, l] + tau * p[i, k]) 56 | p[i, l] = p[i, l] + s * (temp - tau * p[i, l]) 57 | 58 | eig_value_matrix = ti.Matrix.zero(float,A.n,A.n) 59 | spd_matrix = ti.Matrix.zero(float,A.n,A.n) 60 | flag = 0 61 | for i in range(N): 62 | if A[i,i] < -1e-7: 63 | flag = 1 64 | eig_value_matrix[i, i] = 0.0 65 | else: 66 | eig_value_matrix[i, i] = A[i,i] 67 | if flag == 0: 68 | spd_matrix = D 69 | else: 70 | spd_matrix = p @ eig_value_matrix @ p.transpose() 71 | return spd_matrix 72 | 73 | 74 | @ti.func 75 | def flatten3x3(A): 76 | """flatten 3*3 to 9*1""" 77 | flattened = ti.Vector([A[0,0], A[1,0], A[2,0], A[0,1],A[1,1],A[2,1],A[0,2],A[1,2],A[2,2]],float) 78 | return flattened 79 | 80 | @ti.func 81 | def flatten_and_outproduct(A): 82 | #3x3 83 | a0 = A[0,0] 84 | a1 = A[1,0] 85 | a2 = A[2,0] 86 | a3 = A[0,1] 87 | a4 = A[1,1] 88 | a5 = A[2,1] 89 | a6 = A[0,2] 90 | a7 = A[1,2] 91 | a8 = A[2,2] 92 | B = ti.Matrix([[a0 * a0, a0 * a1, a0 * a2, a0 * a3, a0 * a4, a0 * a5, a0 * a6, a0 * a7, a0 * a8], 93 | [a1 * a0, a1 * a1, a1 * a2, a1 * a3, a1 * a4, a1 * a5, a1 * a6, a1 * a7, a1 * a8], 94 | [a2 * a0, a2 * a1, a2 * a2, a2 * a3, a2 * a4, a2 * a5, a2 * a6, a2 * a7, a2 * a8], 95 | [a3 * a0, a3 * a1, a3 * a2, a3 * a3, a3 * a4, a3 * a5, a3 * a6, a3 * a7, a3 * a8], 96 | [a4 * a0, a4 * a1, a4 * a2, a4 * a3, a4 * a4, a4 * a5, a4 * a6, a4 * a7, a4 * a8], 97 | [a5 * a0, a5 * a1, a5 * a2, a5 * a3, a5 * a4, a5 * a5, a5 * a6, a5 * a7, a5 * a8], 98 | [a6 * a0, a6 * a1, a6 * a2, a6 * a3, a6 * a4, a6 * a5, a6 * a6, a6 * a7, a6 * a8], 99 | [a7 * a0, a7 * a1, a7 * a2, a7 * a3, a7 * a4, a7 * a5, a7 * a6, a7 * a7, a7 * a8], 100 | [a8 * a0, a8 * a1, a8 * a2, a8 * a3, a8 * a4, a8 * a5, a8 * a6, a8 * a7, a8 * a8] 101 | ],float) 102 | return B 103 | 104 | 105 | @ti.func 106 | def ssvd(F): 107 | U, sig, V = ti.svd(F) 108 | if U.determinant() < 0: 109 | for i in ti.static(range(3)): 110 | U[i, 2] *= -1 111 | sig[2, 2] = -sig[2, 2] 112 | if V.determinant() < 0: 113 | for i in ti.static(range(3)): 114 | V[i, 2] *= -1 115 | sig[2, 2] = -sig[2, 2] 116 | return U, sig, V 117 | 118 | @ti.func 119 | def svd_rv(F): 120 | #文档中的实现方法,结果相同,但速度慢 121 | U, sig, V = ti.svd(F) 122 | L22 = (U @ (V.transpose())).determinant() 123 | L = ti.Matrix([[1,0,0],[0,1,0],[0,0,L22]],dt=float) 124 | detU = U.determinant() 125 | detV = V.determinant() 126 | if detU < 0.0 and detV > 0.0: 127 | U = U @ L 128 | if detU > 0.0 and detV < 0.0: 129 | V = V @ L 130 | sig[2,2] = sig[2,2] * L22 131 | return U, sig, V 132 | 133 | @ti.kernel 134 | def multiply(ans: ti.template(), k: float, b: ti.template()): 135 | for i in ans: 136 | ans[i] = k * b[i] 137 | 138 | @ti.kernel 139 | def divide(ans: ti.template(), a: ti.template(), b: ti.template()): 140 | for i in ans: 141 | ans[i] = a[i] / b[i] 142 | 143 | 144 | @ti.kernel 145 | def add(ans: ti.template(), a: ti.template(), k: float, b: ti.template()): 146 | for i in ans: 147 | ans[i] = a[i] + k * b[i] 148 | 149 | @ti.kernel 150 | def add_test(ans: ti.template(), a: ti.template(), b: ti.template()): 151 | for i in ans: 152 | ans[i] = a[i] + b[i] 153 | 154 | 155 | @ti.kernel 156 | def dot(a: ti.template(), b: ti.template()) -> float: 157 | ans = 0.0 158 | ti.loop_config(block_dim_adaptive=True) 159 | for i in a: ans += a[i].dot(b[i]) 160 | return ans -------------------------------------------------------------------------------- /model/mesh/Armadillo13K/Armadillo13K.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 0 1 2 -------------------------------------------------------------------------------- /model/mesh/Armadillo13K/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/Armadillo13K/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/cliff/cliff.edge: -------------------------------------------------------------------------------- 1 | 18 2 | 0 0 1 3 | 1 1 2 4 | 2 2 0 5 | 3 0 3 6 | 4 3 1 7 | 5 2 4 8 | 6 4 0 9 | 7 4 5 10 | 8 5 0 11 | 9 0 6 12 | 10 6 3 13 | 11 5 6 14 | 12 2 5 15 | 13 5 3 16 | 14 5 7 17 | 15 7 3 18 | 16 2 7 19 | 17 1 7 20 | -------------------------------------------------------------------------------- /model/mesh/cliff/cliff.ele: -------------------------------------------------------------------------------- 1 | 6 2 | 0 4 7 5 0 3 | 1 4 7 0 6 4 | 2 5 1 0 3 5 | 3 6 1 2 0 6 | 4 6 1 0 4 7 | 5 5 1 4 0 8 | -------------------------------------------------------------------------------- /model/mesh/cliff/cliff.face: -------------------------------------------------------------------------------- 1 | 12 2 | 0 0 1 2 3 | 1 0 3 1 4 | 2 0 2 4 5 | 3 0 4 5 6 | 4 0 6 3 7 | 5 0 5 6 8 | 6 5 4 2 9 | 7 5 3 6 10 | 8 5 7 3 11 | 9 5 2 7 12 | 10 7 2 1 13 | 11 7 1 3 14 | -------------------------------------------------------------------------------- /model/mesh/cliff/cliff.node: -------------------------------------------------------------------------------- 1 | 8 2 | 0 -0.5 0.5 0.5 3 | 1 -0.75 -0.5 -0.75 4 | 2 -0.75 -0.5 0.75 5 | 3 -0.5 0.5 -0.5 6 | 4 0.75 -0.5 -0.75 7 | 5 0.5 0.5 -0.5 8 | 6 0.75 -0.5 0.75 9 | 7 0.5 0.5 0.5 10 | -------------------------------------------------------------------------------- /model/mesh/crack/crack.edge: -------------------------------------------------------------------------------- 1 | 114 2 | 0 0 1 3 | 1 1 2 4 | 2 2 0 5 | 3 2 3 6 | 4 3 0 7 | 5 0 4 8 | 6 4 1 9 | 7 0 5 10 | 8 5 4 11 | 9 3 6 12 | 10 6 0 13 | 11 6 5 14 | 12 4 7 15 | 13 7 1 16 | 14 5 7 17 | 15 7 8 18 | 16 8 1 19 | 17 1 9 20 | 18 9 2 21 | 19 8 9 22 | 20 10 9 23 | 21 9 11 24 | 22 11 10 25 | 23 10 12 26 | 24 12 13 27 | 25 13 10 28 | 26 11 12 29 | 27 13 3 30 | 28 3 10 31 | 29 3 14 32 | 30 14 10 33 | 31 14 9 34 | 32 8 15 35 | 33 15 9 36 | 34 15 11 37 | 35 14 2 38 | 36 11 16 39 | 37 16 12 40 | 38 15 16 41 | 39 16 13 42 | 40 13 17 43 | 41 17 3 44 | 42 16 17 45 | 43 18 19 46 | 44 19 20 47 | 45 20 18 48 | 46 18 21 49 | 47 21 22 50 | 48 22 18 51 | 49 22 23 52 | 50 23 18 53 | 51 20 21 54 | 52 18 6 55 | 53 6 19 56 | 54 23 6 57 | 55 21 23 58 | 56 21 24 59 | 57 24 25 60 | 58 25 21 61 | 59 21 26 62 | 60 26 24 63 | 61 20 26 64 | 62 25 23 65 | 63 27 28 66 | 64 28 26 67 | 65 26 27 68 | 66 27 19 69 | 67 19 29 70 | 68 29 27 71 | 69 27 30 72 | 70 30 28 73 | 71 29 30 74 | 72 27 31 75 | 73 31 19 76 | 74 26 31 77 | 75 28 24 78 | 76 28 32 79 | 77 32 33 80 | 78 33 28 81 | 79 30 32 82 | 80 33 24 83 | 81 20 31 84 | 82 29 32 85 | 83 19 17 86 | 84 17 29 87 | 85 17 32 88 | 86 34 25 89 | 87 24 34 90 | 88 34 23 91 | 89 34 7 92 | 90 5 34 93 | 91 34 8 94 | 92 5 35 95 | 93 35 34 96 | 94 34 36 97 | 95 36 8 98 | 96 24 36 99 | 97 35 23 100 | 98 6 37 101 | 99 37 19 102 | 100 6 35 103 | 101 3 37 104 | 102 36 38 105 | 103 38 15 106 | 104 15 36 107 | 105 33 36 108 | 106 33 38 109 | 107 39 16 110 | 108 15 39 111 | 109 39 17 112 | 110 39 38 113 | 111 33 39 114 | 112 39 32 115 | 113 17 37 116 | -------------------------------------------------------------------------------- /model/mesh/crack/crack.ele: -------------------------------------------------------------------------------- 1 | 78 2 | 0 20 36 34 21 3 | 1 13 15 14 36 4 | 2 30 21 32 33 5 | 3 17 13 38 39 6 | 4 24 29 28 25 7 | 5 16 10 36 39 8 | 6 6 0 30 31 9 | 7 20 35 21 34 10 | 8 11 35 10 12 11 | 9 2 6 30 31 12 | 10 0 6 2 31 13 | 11 0 6 30 33 14 | 12 4 3 29 30 15 | 13 20 32 31 21 16 | 14 36 21 23 39 17 | 15 28 25 30 33 18 | 16 23 21 27 39 19 | 17 36 25 38 39 20 | 18 21 20 30 31 21 | 19 2 6 4 30 22 | 20 14 38 13 37 23 | 21 25 23 26 29 24 | 22 25 24 26 37 25 | 23 3 5 4 29 26 | 24 36 15 16 39 27 | 25 4 3 30 33 28 | 26 20 32 21 22 29 | 27 16 10 34 36 30 | 28 30 21 31 32 31 | 29 23 21 30 33 32 | 30 23 37 36 25 33 | 31 25 23 29 30 34 | 32 23 25 27 33 35 | 33 9 3 7 28 36 | 34 3 28 29 30 37 | 35 21 20 23 30 38 | 36 21 23 27 33 39 | 37 0 30 32 33 40 | 38 25 23 27 39 41 | 39 3 9 5 28 42 | 40 36 23 25 39 43 | 41 20 36 21 23 44 | 42 5 3 28 29 45 | 43 11 36 16 34 46 | 44 25 23 30 33 47 | 45 14 38 19 13 48 | 46 29 28 25 30 49 | 47 24 29 25 26 50 | 48 1 0 2 31 51 | 49 13 36 38 39 52 | 50 14 13 36 37 53 | 51 11 36 15 16 54 | 52 6 4 30 33 55 | 53 0 30 31 32 56 | 54 1 0 31 32 57 | 55 11 35 34 10 58 | 56 20 35 22 21 59 | 57 10 11 16 34 60 | 58 3 7 28 33 61 | 59 3 28 30 33 62 | 60 6 8 4 33 63 | 61 8 3 4 33 64 | 62 21 0 32 33 65 | 63 7 25 28 33 66 | 64 13 15 36 39 67 | 65 13 36 37 38 68 | 66 13 19 17 38 69 | 67 23 37 25 26 70 | 68 37 36 25 38 71 | 69 25 24 37 38 72 | 70 35 21 34 39 73 | 71 36 34 21 39 74 | 72 35 34 10 39 75 | 73 10 34 36 39 76 | 74 13 18 15 39 77 | 75 18 16 15 39 78 | 76 25 17 38 39 79 | 77 10 21 35 39 80 | -------------------------------------------------------------------------------- /model/mesh/crack/crack.face: -------------------------------------------------------------------------------- 1 | 76 2 | 0 0 1 2 3 | 1 0 2 3 4 | 2 0 4 1 5 | 3 0 5 4 6 | 4 0 3 6 7 | 5 0 6 5 8 | 6 4 7 1 9 | 7 4 5 7 10 | 8 1 7 8 11 | 9 1 9 2 12 | 10 1 8 9 13 | 11 10 9 11 14 | 12 10 12 13 15 | 13 10 11 12 16 | 14 10 13 3 17 | 15 10 3 14 18 | 16 10 14 9 19 | 17 9 8 15 20 | 18 9 15 11 21 | 19 9 14 2 22 | 20 11 16 12 23 | 21 11 15 16 24 | 22 2 14 3 25 | 23 13 12 16 26 | 24 13 17 3 27 | 25 13 16 17 28 | 26 18 19 20 29 | 27 18 21 22 30 | 28 18 22 23 31 | 29 18 20 21 32 | 30 18 6 19 33 | 31 18 23 6 34 | 32 21 23 22 35 | 33 21 24 25 36 | 34 21 26 24 37 | 35 21 20 26 38 | 36 21 25 23 39 | 37 27 28 26 40 | 38 27 19 29 41 | 39 27 30 28 42 | 40 27 29 30 43 | 41 27 31 19 44 | 42 27 26 31 45 | 43 28 24 26 46 | 44 28 32 33 47 | 45 28 30 32 48 | 46 28 33 24 49 | 47 26 20 31 50 | 48 20 19 31 51 | 49 29 32 30 52 | 50 29 19 17 53 | 51 29 17 32 54 | 52 34 25 24 55 | 53 34 23 25 56 | 54 34 7 5 57 | 55 34 8 7 58 | 56 34 5 35 59 | 57 34 36 8 60 | 58 34 24 36 61 | 59 34 35 23 62 | 60 6 37 19 63 | 61 6 35 5 64 | 62 6 3 37 65 | 63 6 23 35 66 | 64 36 38 15 67 | 65 36 24 33 68 | 66 36 15 8 69 | 67 36 33 38 70 | 68 39 16 15 71 | 69 39 17 16 72 | 70 39 38 33 73 | 71 39 15 38 74 | 72 39 32 17 75 | 73 39 33 32 76 | 74 17 37 3 77 | 75 17 19 37 78 | -------------------------------------------------------------------------------- /model/mesh/crack/crack.node: -------------------------------------------------------------------------------- 1 | 40 2 | 0 -1.0 -0.5 -2.0 3 | 1 -1.0 0.5 -2.0 4 | 2 -0.5 0.5 -2.0 5 | 3 0.5 -0.5 -2.0 6 | 4 0.0 0.0 -2.0 7 | 5 0.5 0.5 -2.0 8 | 6 -0.5 -0.5 -2.0 9 | 7 1.0 -0.5 -2.0 10 | 8 0.0 -0.5 -2.0 11 | 9 1.0 0.5 -2.0 12 | 10 -1.0 -0.5 2.0 13 | 11 -0.5 0.5 2.0 14 | 12 -1.0 0.5 2.0 15 | 13 0.5 -0.5 2.0 16 | 14 0.5 0.5 2.0 17 | 15 0.0 0.0 2.0 18 | 16 -0.5 -0.5 2.0 19 | 17 1.0 -0.5 2.0 20 | 18 0.0 -0.5 2.0 21 | 19 1.0 0.5 2.0 22 | 20 -0.5 0.5 0.0 23 | 21 -1.0 -0.5 0.0 24 | 22 -1.0 0.5 0.0 25 | 23 0.0 0.0 0.0 26 | 24 1.0 0.5 0.0 27 | 25 1.0 -0.5 0.0 28 | 26 0.5 0.5 0.0 29 | 27 0.0 -0.5 0.0 30 | 28 1.0 0.5 -1.0 31 | 29 0.5 0.5 -1.0 32 | 30 0.0 0.0 -1.0 33 | 31 -0.5 0.5 -1.0 34 | 32 -1.0 0.5 -1.0 35 | 33 0.0 -0.5 -1.0 36 | 34 -0.5 0.5 1.0 37 | 35 -1.0 0.5 1.0 38 | 36 0.0 0.0 1.0 39 | 37 0.5 0.5 1.0 40 | 38 1.0 0.5 1.0 41 | 39 0.0 -0.5 1.0 42 | -------------------------------------------------------------------------------- /model/mesh/cube/cube.edge: -------------------------------------------------------------------------------- 1 | 18 1 2 | 0 0 1 -1 3 | 1 1 2 -1 4 | 2 2 0 -1 5 | 3 2 3 -1 6 | 4 3 0 -1 7 | 5 0 4 -1 8 | 6 4 5 -1 9 | 7 5 0 -1 10 | 8 0 6 -1 11 | 9 6 1 -1 12 | 10 5 6 -1 13 | 11 3 4 -1 14 | 12 4 7 -1 15 | 13 7 5 -1 16 | 14 3 7 -1 17 | 15 6 7 -1 18 | 16 7 1 -1 19 | 17 1 3 -1 20 | -------------------------------------------------------------------------------- /model/mesh/cube/cube.ele: -------------------------------------------------------------------------------- 1 | 6 2 | 0 4 7 0 6 3 | 1 1 5 0 3 4 | 2 2 5 0 4 5 | 3 2 5 3 0 6 | 4 1 5 7 0 7 | 5 4 7 5 0 8 | -------------------------------------------------------------------------------- /model/mesh/cube/cube.face: -------------------------------------------------------------------------------- 1 | 12 2 | 0 0 1 2 3 | 1 0 2 3 4 | 2 0 4 5 5 | 3 0 6 1 6 | 4 0 5 6 7 | 5 0 3 4 8 | 6 4 7 5 9 | 7 4 3 7 10 | 8 6 7 1 11 | 9 6 5 7 12 | 10 1 3 2 13 | 11 1 7 3 14 | -------------------------------------------------------------------------------- /model/mesh/cube/cube.node: -------------------------------------------------------------------------------- 1 | 8 2 | 0 -0.5 -0.5 0.5 3 | 1 0.5 -0.5 0.5 4 | 2 -0.5 0.5 0.5 5 | 3 0.5 0.5 0.5 6 | 4 -0.5 0.5 -0.5 7 | 5 0.5 0.5 -0.5 8 | 6 -0.5 -0.5 -0.5 9 | 7 0.5 -0.5 -0.5 10 | -------------------------------------------------------------------------------- /model/mesh/cube/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/cube/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/cube_10/cube_10.edge: -------------------------------------------------------------------------------- 1 | 1 2 | 0 36 1 3 | -------------------------------------------------------------------------------- /model/mesh/cube_10/cube_10.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 36 1 0 3 | -------------------------------------------------------------------------------- /model/mesh/cube_10/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/cube_10/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/cube_2/cube_2.ele: -------------------------------------------------------------------------------- 1 | 6 2 | 0 0 4 6 5 3 | 1 3 6 2 0 4 | 2 0 4 7 6 5 | 3 3 6 0 7 6 | 4 2 0 6 1 7 | 5 6 0 5 1 8 | -------------------------------------------------------------------------------- /model/mesh/cube_2/cube_2.node: -------------------------------------------------------------------------------- 1 | 8 2 | 0 0.0 0.0 0.0 3 | 1 1.0 0.0 0.0 4 | 2 1.0 0.0 1.0 5 | 3 0.0 0.0 1.0 6 | 4 0.0 1.0 0.0 7 | 5 1.0 1.0 0.0 8 | 6 1.0 1.0 1.0 9 | 7 0.0 1.0 1.0 10 | -------------------------------------------------------------------------------- /model/mesh/cube_20/cube_20.edge: -------------------------------------------------------------------------------- 1 | 1 2 | 0 121 2628 3 | -------------------------------------------------------------------------------- /model/mesh/cube_20/cube_20.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 121 2628 232 3 | -------------------------------------------------------------------------------- /model/mesh/cube_20/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/cube_20/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/cube_40/cube_40.edge: -------------------------------------------------------------------------------- 1 | 1 2 | 0 441 17801 3 | -------------------------------------------------------------------------------- /model/mesh/cube_40/cube_40.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 441 17801 862 3 | -------------------------------------------------------------------------------- /model/mesh/cube_40/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/cube_40/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/cube_6/cube_6.edge: -------------------------------------------------------------------------------- 1 | 1 2 | 0 16 1 3 | -------------------------------------------------------------------------------- /model/mesh/cube_6/cube_6.ele: -------------------------------------------------------------------------------- 1 | 432 2 | 0 16 1 0 91 3 | 1 16 1 92 0 4 | 2 17 2 1 96 5 | 3 17 2 95 1 6 | 4 18 3 2 98 7 | 5 18 3 97 2 8 | 6 16 4 91 0 9 | 7 16 4 0 93 10 | 8 19 5 4 100 11 | 9 16 5 91 4 12 | 10 5 4 16 19 13 | 11 16 5 1 91 14 | 12 17 5 96 1 15 | 13 5 1 17 16 16 | 14 20 6 5 103 17 | 15 17 6 96 5 18 | 16 6 5 17 20 19 | 17 17 6 2 96 20 | 18 18 6 98 2 21 | 19 6 2 18 17 22 | 20 21 7 6 104 23 | 21 18 7 98 6 24 | 22 7 6 18 21 25 | 23 18 7 3 98 26 | 24 18 7 99 3 27 | 25 19 8 100 4 28 | 26 19 8 4 101 29 | 27 22 9 8 107 30 | 28 19 9 100 8 31 | 29 9 8 19 22 32 | 30 19 9 5 100 33 | 31 20 9 103 5 34 | 32 9 5 20 19 35 | 33 23 10 9 109 36 | 34 20 10 103 9 37 | 35 10 9 20 23 38 | 36 20 10 6 103 39 | 37 21 10 104 6 40 | 38 10 6 21 20 41 | 39 24 11 10 102 42 | 40 21 11 104 10 43 | 41 11 10 21 24 44 | 42 21 11 7 104 45 | 43 21 11 105 7 46 | 44 22 12 107 8 47 | 45 22 12 8 106 48 | 46 22 13 107 12 49 | 47 22 13 12 108 50 | 48 22 13 9 107 51 | 49 23 13 109 9 52 | 50 13 9 23 22 53 | 51 23 14 109 13 54 | 52 23 14 13 110 55 | 53 23 14 10 109 56 | 54 24 14 102 10 57 | 55 14 10 24 23 58 | 56 24 15 102 14 59 | 57 24 15 14 111 60 | 58 24 15 11 102 61 | 59 24 15 112 11 62 | 60 16 25 0 92 63 | 61 16 25 93 0 64 | 62 26 25 41 16 65 | 63 41 26 116 25 66 | 64 16 26 25 92 67 | 65 16 26 92 1 68 | 66 17 26 1 95 69 | 67 26 1 16 17 70 | 68 27 26 42 17 71 | 69 42 27 117 26 72 | 70 17 27 26 95 73 | 71 17 27 95 2 74 | 72 18 27 2 97 75 | 73 27 2 17 18 76 | 74 28 27 43 18 77 | 75 43 28 118 27 78 | 76 18 28 27 97 79 | 77 18 28 97 3 80 | 78 18 28 3 99 81 | 79 29 4 19 16 82 | 80 29 25 16 41 83 | 81 16 29 93 25 84 | 82 41 29 25 115 85 | 83 19 29 101 4 86 | 84 16 29 4 93 87 | 85 30 29 44 19 88 | 86 30 29 16 41 89 | 87 30 29 41 44 90 | 88 30 29 19 16 91 | 89 30 5 16 19 92 | 90 30 5 20 17 93 | 91 30 26 41 16 94 | 92 30 26 17 42 95 | 93 30 26 16 17 96 | 94 30 26 42 41 97 | 95 30 5 19 20 98 | 96 30 5 17 16 99 | 97 31 30 45 20 100 | 98 31 30 17 42 101 | 99 31 30 42 45 102 | 100 31 30 20 17 103 | 101 31 6 17 20 104 | 102 31 6 21 18 105 | 103 31 27 42 17 106 | 104 31 27 18 43 107 | 105 31 27 17 18 108 | 106 31 27 43 42 109 | 107 31 6 20 21 110 | 108 31 6 18 17 111 | 109 32 31 46 21 112 | 110 32 31 18 43 113 | 111 32 31 43 46 114 | 112 32 31 21 18 115 | 113 32 7 18 21 116 | 114 32 28 43 18 117 | 115 18 32 28 99 118 | 116 43 32 119 28 119 | 117 21 32 7 105 120 | 118 18 32 99 7 121 | 119 33 8 22 19 122 | 120 33 29 19 44 123 | 121 19 33 101 29 124 | 122 44 33 29 94 125 | 123 22 33 106 8 126 | 124 19 33 8 101 127 | 125 34 33 47 22 128 | 126 34 33 19 44 129 | 127 34 33 44 47 130 | 128 34 33 22 19 131 | 129 34 9 19 22 132 | 130 34 9 23 20 133 | 131 34 30 44 19 134 | 132 34 30 20 45 135 | 133 34 30 19 20 136 | 134 34 30 45 44 137 | 135 34 9 22 23 138 | 136 34 9 20 19 139 | 137 35 34 48 23 140 | 138 35 34 20 45 141 | 139 35 34 45 48 142 | 140 35 34 23 20 143 | 141 35 10 20 23 144 | 142 35 10 24 21 145 | 143 35 31 45 20 146 | 144 35 31 21 46 147 | 145 35 31 20 21 148 | 146 35 31 46 45 149 | 147 35 10 23 24 150 | 148 35 10 21 20 151 | 149 36 35 49 24 152 | 150 36 35 21 46 153 | 151 36 35 46 49 154 | 152 36 35 24 21 155 | 153 36 11 21 24 156 | 154 36 32 46 21 157 | 155 21 36 32 105 158 | 156 46 36 123 32 159 | 157 24 36 11 112 160 | 158 21 36 105 11 161 | 159 22 37 108 12 162 | 160 37 33 22 47 163 | 161 22 37 106 33 164 | 162 47 37 33 122 165 | 163 22 37 12 106 166 | 164 38 37 22 47 167 | 165 47 38 37 113 168 | 166 22 38 108 37 169 | 167 22 38 13 108 170 | 168 23 38 110 13 171 | 169 38 34 47 22 172 | 170 38 34 23 48 173 | 171 38 34 22 23 174 | 172 38 34 48 47 175 | 173 38 13 23 22 176 | 174 39 38 23 48 177 | 175 48 39 38 125 178 | 176 23 39 110 38 179 | 177 23 39 14 110 180 | 178 24 39 111 14 181 | 179 39 35 48 23 182 | 180 39 35 24 49 183 | 181 39 35 23 24 184 | 182 39 35 49 48 185 | 183 39 14 24 23 186 | 184 40 39 24 49 187 | 185 49 40 39 124 188 | 186 24 40 111 39 189 | 187 24 40 15 111 190 | 188 40 36 49 24 191 | 189 24 40 36 112 192 | 190 49 40 114 36 193 | 191 24 40 112 15 194 | 192 41 50 25 116 195 | 193 41 50 115 25 196 | 194 51 50 66 41 197 | 195 66 51 128 50 198 | 196 41 51 50 116 199 | 197 41 51 116 26 200 | 198 42 51 26 117 201 | 199 51 26 41 42 202 | 200 52 51 67 42 203 | 201 67 52 131 51 204 | 202 42 52 51 117 205 | 203 42 52 117 27 206 | 204 43 52 27 118 207 | 205 52 27 42 43 208 | 206 53 52 68 43 209 | 207 68 53 133 52 210 | 208 43 53 52 118 211 | 209 43 53 118 28 212 | 210 43 53 28 119 213 | 211 54 29 44 41 214 | 212 54 50 41 66 215 | 213 41 54 115 50 216 | 214 66 54 50 121 217 | 215 44 54 94 29 218 | 216 41 54 29 115 219 | 217 55 54 69 44 220 | 218 55 54 41 66 221 | 219 55 54 66 69 222 | 220 55 54 44 41 223 | 221 55 30 41 44 224 | 222 55 30 45 42 225 | 223 55 51 66 41 226 | 224 55 51 42 67 227 | 225 55 51 41 42 228 | 226 55 51 67 66 229 | 227 55 30 44 45 230 | 228 55 30 42 41 231 | 229 56 55 70 45 232 | 230 56 55 42 67 233 | 231 56 55 67 70 234 | 232 56 55 45 42 235 | 233 56 31 42 45 236 | 234 56 31 46 43 237 | 235 56 52 67 42 238 | 236 56 52 43 68 239 | 237 56 52 42 43 240 | 238 56 52 68 67 241 | 239 56 31 45 46 242 | 240 56 31 43 42 243 | 241 57 56 71 46 244 | 242 57 56 43 68 245 | 243 57 56 68 71 246 | 244 57 56 46 43 247 | 245 57 32 43 46 248 | 246 57 53 68 43 249 | 247 43 57 53 119 250 | 248 68 57 134 53 251 | 249 46 57 32 123 252 | 250 43 57 119 32 253 | 251 58 33 47 44 254 | 252 58 54 44 69 255 | 253 44 58 94 54 256 | 254 69 58 54 120 257 | 255 47 58 122 33 258 | 256 44 58 33 94 259 | 257 59 58 72 47 260 | 258 59 58 44 69 261 | 259 59 58 69 72 262 | 260 59 58 47 44 263 | 261 59 34 44 47 264 | 262 59 34 48 45 265 | 263 59 55 69 44 266 | 264 59 55 45 70 267 | 265 59 55 44 45 268 | 266 59 55 70 69 269 | 267 59 34 47 48 270 | 268 59 34 45 44 271 | 269 60 59 73 48 272 | 270 60 59 45 70 273 | 271 60 59 70 73 274 | 272 60 59 48 45 275 | 273 60 35 45 48 276 | 274 60 35 49 46 277 | 275 60 56 70 45 278 | 276 60 56 46 71 279 | 277 60 56 45 46 280 | 278 60 56 71 70 281 | 279 60 35 48 49 282 | 280 60 35 46 45 283 | 281 61 60 74 49 284 | 282 61 60 46 71 285 | 283 61 60 71 74 286 | 284 61 60 49 46 287 | 285 61 36 46 49 288 | 286 61 57 71 46 289 | 287 46 61 57 123 290 | 288 71 61 138 57 291 | 289 49 61 36 114 292 | 290 46 61 123 36 293 | 291 47 62 113 37 294 | 292 62 58 47 72 295 | 293 47 62 122 58 296 | 294 72 62 58 136 297 | 295 47 62 37 122 298 | 296 63 62 47 72 299 | 297 72 63 62 127 300 | 298 47 63 113 62 301 | 299 47 63 38 113 302 | 300 48 63 125 38 303 | 301 63 59 72 47 304 | 302 63 59 48 73 305 | 303 63 59 47 48 306 | 304 63 59 73 72 307 | 305 63 38 48 47 308 | 306 64 63 48 73 309 | 307 73 64 63 143 310 | 308 48 64 125 63 311 | 309 48 64 39 125 312 | 310 49 64 124 39 313 | 311 64 60 73 48 314 | 312 64 60 49 74 315 | 313 64 60 48 49 316 | 314 64 60 74 73 317 | 315 64 39 49 48 318 | 316 65 64 49 74 319 | 317 74 65 64 141 320 | 318 49 65 124 64 321 | 319 49 65 40 124 322 | 320 65 61 74 49 323 | 321 49 65 61 114 324 | 322 74 65 126 61 325 | 323 49 65 114 40 326 | 324 66 75 50 128 327 | 325 66 75 121 50 328 | 326 66 76 130 75 329 | 327 66 76 75 128 330 | 328 66 76 128 51 331 | 329 67 76 51 131 332 | 330 76 51 66 67 333 | 331 67 77 132 76 334 | 332 67 77 76 131 335 | 333 67 77 131 52 336 | 334 68 77 52 133 337 | 335 77 52 67 68 338 | 336 68 78 135 77 339 | 337 68 78 77 133 340 | 338 68 78 133 53 341 | 339 68 78 53 134 342 | 340 79 54 69 66 343 | 341 66 79 75 130 344 | 342 66 79 121 75 345 | 343 69 79 120 54 346 | 344 66 79 54 121 347 | 345 69 80 129 79 348 | 346 66 80 79 130 349 | 347 80 79 69 66 350 | 348 80 55 66 69 351 | 349 80 55 70 67 352 | 350 66 80 130 76 353 | 351 67 80 76 132 354 | 352 80 76 66 67 355 | 353 80 55 69 70 356 | 354 80 55 67 66 357 | 355 70 81 140 80 358 | 356 67 81 80 132 359 | 357 81 80 70 67 360 | 358 81 56 67 70 361 | 359 81 56 71 68 362 | 360 67 81 132 77 363 | 361 68 81 77 135 364 | 362 81 77 67 68 365 | 363 81 56 70 71 366 | 364 81 56 68 67 367 | 365 71 82 139 81 368 | 366 68 82 81 135 369 | 367 82 81 71 68 370 | 368 82 57 68 71 371 | 369 68 82 135 78 372 | 370 68 82 78 134 373 | 371 71 82 57 138 374 | 372 68 82 134 57 375 | 373 83 58 72 69 376 | 374 69 83 79 129 377 | 375 69 83 120 79 378 | 376 72 83 136 58 379 | 377 69 83 58 120 380 | 378 72 84 137 83 381 | 379 69 84 83 129 382 | 380 84 83 72 69 383 | 381 84 59 69 72 384 | 382 84 59 73 70 385 | 383 69 84 129 80 386 | 384 70 84 80 140 387 | 385 84 80 69 70 388 | 386 84 59 72 73 389 | 387 84 59 70 69 390 | 388 73 85 144 84 391 | 389 70 85 84 140 392 | 390 85 84 73 70 393 | 391 85 60 70 73 394 | 392 85 60 74 71 395 | 393 70 85 140 81 396 | 394 71 85 81 139 397 | 395 85 81 70 71 398 | 396 85 60 73 74 399 | 397 85 60 71 70 400 | 398 74 86 142 85 401 | 399 71 86 85 139 402 | 400 86 85 74 71 403 | 401 86 61 71 74 404 | 402 71 86 139 82 405 | 403 71 86 82 138 406 | 404 74 86 61 126 407 | 405 71 86 138 61 408 | 406 72 87 127 62 409 | 407 72 87 83 137 410 | 408 72 87 136 83 411 | 409 72 87 62 136 412 | 410 72 88 87 137 413 | 411 72 88 127 87 414 | 412 72 88 63 127 415 | 413 73 88 143 63 416 | 414 72 88 137 84 417 | 415 73 88 84 144 418 | 416 88 84 72 73 419 | 417 88 63 73 72 420 | 418 73 89 88 144 421 | 419 73 89 143 88 422 | 420 73 89 64 143 423 | 421 74 89 141 64 424 | 422 73 89 144 85 425 | 423 74 89 85 142 426 | 424 89 85 73 74 427 | 425 89 64 74 73 428 | 426 74 90 89 142 429 | 427 74 90 141 89 430 | 428 74 90 65 141 431 | 429 74 90 142 86 432 | 430 74 90 86 126 433 | 431 74 90 126 65 434 | -------------------------------------------------------------------------------- /model/mesh/cube_6/cube_6.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 16 1 0 3 | -------------------------------------------------------------------------------- /model/mesh/cube_6/cube_6.node: -------------------------------------------------------------------------------- 1 | 145 2 | 0 0.25 0.25 0.25 3 | 1 0.41666666666666669 0.25 0.25 4 | 2 0.58333333333333337 0.25 0.25 5 | 3 0.75 0.25 0.25 6 | 4 0.25 0.41666666666666669 0.25 7 | 5 0.41666666666666669 0.41666666666666669 0.25 8 | 6 0.58333333333333337 0.41666666666666669 0.25 9 | 7 0.75 0.41666666666666669 0.25 10 | 8 0.25 0.58333333333333337 0.25 11 | 9 0.41666666666666669 0.58333333333333337 0.25 12 | 10 0.58333333333333337 0.58333333333333337 0.25 13 | 11 0.75 0.58333333333333337 0.25 14 | 12 0.25 0.75 0.25 15 | 13 0.41666666666666669 0.75 0.25 16 | 14 0.58333333333333337 0.75 0.25 17 | 15 0.75 0.75 0.25 18 | 16 0.33333333333333331 0.33333333333333331 0.33333333333333331 19 | 17 0.5 0.33333333333333331 0.33333333333333331 20 | 18 0.66666666666666663 0.33333333333333331 0.33333333333333331 21 | 19 0.33333333333333331 0.5 0.33333333333333331 22 | 20 0.5 0.5 0.33333333333333331 23 | 21 0.66666666666666663 0.5 0.33333333333333331 24 | 22 0.33333333333333331 0.66666666666666663 0.33333333333333331 25 | 23 0.5 0.66666666666666663 0.33333333333333331 26 | 24 0.66666666666666663 0.66666666666666663 0.33333333333333331 27 | 25 0.25 0.25 0.41666666666666669 28 | 26 0.41666666666666669 0.25 0.41666666666666669 29 | 27 0.58333333333333337 0.25 0.41666666666666669 30 | 28 0.75 0.25 0.41666666666666669 31 | 29 0.25 0.41666666666666669 0.41666666666666669 32 | 30 0.41666666666666669 0.41666666666666669 0.41666666666666669 33 | 31 0.58333333333333337 0.41666666666666669 0.41666666666666669 34 | 32 0.75 0.41666666666666669 0.41666666666666669 35 | 33 0.25 0.58333333333333337 0.41666666666666669 36 | 34 0.41666666666666669 0.58333333333333337 0.41666666666666669 37 | 35 0.58333333333333337 0.58333333333333337 0.41666666666666669 38 | 36 0.75 0.58333333333333337 0.41666666666666669 39 | 37 0.25 0.75 0.41666666666666669 40 | 38 0.41666666666666669 0.75 0.41666666666666669 41 | 39 0.58333333333333337 0.75 0.41666666666666669 42 | 40 0.75 0.75 0.41666666666666669 43 | 41 0.33333333333333331 0.33333333333333331 0.5 44 | 42 0.5 0.33333333333333331 0.5 45 | 43 0.66666666666666663 0.33333333333333331 0.5 46 | 44 0.33333333333333331 0.5 0.5 47 | 45 0.5 0.5 0.5 48 | 46 0.66666666666666663 0.5 0.5 49 | 47 0.33333333333333331 0.66666666666666663 0.5 50 | 48 0.5 0.66666666666666663 0.5 51 | 49 0.66666666666666663 0.66666666666666663 0.5 52 | 50 0.25 0.25 0.58333333333333337 53 | 51 0.41666666666666669 0.25 0.58333333333333337 54 | 52 0.58333333333333337 0.25 0.58333333333333337 55 | 53 0.75 0.25 0.58333333333333337 56 | 54 0.25 0.41666666666666669 0.58333333333333337 57 | 55 0.41666666666666669 0.41666666666666669 0.58333333333333337 58 | 56 0.58333333333333337 0.41666666666666669 0.58333333333333337 59 | 57 0.75 0.41666666666666669 0.58333333333333337 60 | 58 0.25 0.58333333333333337 0.58333333333333337 61 | 59 0.41666666666666669 0.58333333333333337 0.58333333333333337 62 | 60 0.58333333333333337 0.58333333333333337 0.58333333333333337 63 | 61 0.75 0.58333333333333337 0.58333333333333337 64 | 62 0.25 0.75 0.58333333333333337 65 | 63 0.41666666666666669 0.75 0.58333333333333337 66 | 64 0.58333333333333337 0.75 0.58333333333333337 67 | 65 0.75 0.75 0.58333333333333337 68 | 66 0.33333333333333331 0.33333333333333331 0.66666666666666663 69 | 67 0.5 0.33333333333333331 0.66666666666666663 70 | 68 0.66666666666666663 0.33333333333333331 0.66666666666666663 71 | 69 0.33333333333333331 0.5 0.66666666666666663 72 | 70 0.5 0.5 0.66666666666666663 73 | 71 0.66666666666666663 0.5 0.66666666666666663 74 | 72 0.33333333333333331 0.66666666666666663 0.66666666666666663 75 | 73 0.5 0.66666666666666663 0.66666666666666663 76 | 74 0.66666666666666663 0.66666666666666663 0.66666666666666663 77 | 75 0.25 0.25 0.75 78 | 76 0.41666666666666669 0.25 0.75 79 | 77 0.58333333333333337 0.25 0.75 80 | 78 0.75 0.25 0.75 81 | 79 0.25 0.41666666666666669 0.75 82 | 80 0.41666666666666669 0.41666666666666669 0.75 83 | 81 0.58333333333333337 0.41666666666666669 0.75 84 | 82 0.75 0.41666666666666669 0.75 85 | 83 0.25 0.58333333333333337 0.75 86 | 84 0.41666666666666669 0.58333333333333337 0.75 87 | 85 0.58333333333333337 0.58333333333333337 0.75 88 | 86 0.75 0.58333333333333337 0.75 89 | 87 0.25 0.75 0.75 90 | 88 0.41666666666666669 0.75 0.75 91 | 89 0.58333333333333337 0.75 0.75 92 | 90 0.75 0.75 0.75 93 | 91 0.33333333333333331 0.33333333333333331 0.24999999254941963 94 | 92 0.33333333333333331 0.24999999254941963 0.33333333333333331 95 | 93 0.24999999254941963 0.33333333333333331 0.33333333333333331 96 | 94 0.24999999254941963 0.5 0.5 97 | 95 0.5 0.24999999254941963 0.33333333333333331 98 | 96 0.5 0.33333333333333331 0.24999999254941963 99 | 97 0.66666666666666663 0.25000000745058171 0.33333333333333331 100 | 98 0.66666666666666663 0.33333333333333331 0.25000000745058171 101 | 99 0.75 0.33333333333333331 0.33333333333333331 102 | 100 0.33333333333333331 0.5 0.24999999254941963 103 | 101 0.24999999254941963 0.5 0.33333333333333331 104 | 102 0.66666666666666663 0.66666666666666663 0.25000000745058171 105 | 103 0.5 0.5 0.24999999254941963 106 | 104 0.66666666666666663 0.5 0.25000000745058171 107 | 105 0.75 0.5 0.33333333333333331 108 | 106 0.25000000745058171 0.66666666666666663 0.33333333333333331 109 | 107 0.33333333333333331 0.66666666666666663 0.25000000745058171 110 | 108 0.33333333333333331 0.75 0.33333333333333331 111 | 109 0.5 0.66666666666666663 0.25000000745058171 112 | 110 0.5 0.75 0.33333333333333331 113 | 111 0.66666666666666663 0.75 0.33333333333333331 114 | 112 0.75 0.66666666666666663 0.33333333333333331 115 | 113 0.33333333333333331 0.75 0.5 116 | 114 0.75 0.66666666666666663 0.5 117 | 115 0.24999999254941963 0.33333333333333331 0.5 118 | 116 0.33333333333333331 0.24999999254941963 0.5 119 | 117 0.5 0.24999999254941963 0.5 120 | 118 0.66666666666666663 0.25000000745058171 0.5 121 | 119 0.75 0.33333333333333331 0.5 122 | 120 0.25000000745058171 0.5 0.66666666666666663 123 | 121 0.25000000745058171 0.33333333333333331 0.66666666666666663 124 | 122 0.25000000745058171 0.66666666666666663 0.5 125 | 123 0.75 0.5 0.5 126 | 124 0.66666666666666663 0.75 0.5 127 | 125 0.5 0.75 0.5 128 | 126 0.75 0.66666666666666663 0.66666666666666663 129 | 127 0.33333333333333331 0.75 0.66666666666666663 130 | 128 0.33333333333333331 0.25000000745058171 0.66666666666666663 131 | 129 0.33333333333333331 0.5 0.75 132 | 130 0.33333333333333331 0.33333333333333331 0.75 133 | 131 0.5 0.25000000745058171 0.66666666666666663 134 | 132 0.5 0.33333333333333331 0.75 135 | 133 0.66666666666666663 0.25000000745058171 0.66666666666666663 136 | 134 0.75 0.33333333333333331 0.66666666666666663 137 | 135 0.66666666666666663 0.33333333333333331 0.75 138 | 136 0.25000000745058171 0.66666666666666663 0.66666666666666663 139 | 137 0.33333333333333331 0.66666666666666663 0.75 140 | 138 0.75 0.5 0.66666666666666663 141 | 139 0.66666666666666663 0.5 0.75 142 | 140 0.5 0.5 0.75 143 | 141 0.66666666666666663 0.75 0.66666666666666663 144 | 142 0.66666666666666663 0.66666666666666663 0.75 145 | 143 0.5 0.75 0.66666666666666663 146 | 144 0.5 0.66666666666666663 0.75 147 | -------------------------------------------------------------------------------- /model/mesh/cube_8/cube_8.edge: -------------------------------------------------------------------------------- 1 | 1 2 | 0 25 206 3 | -------------------------------------------------------------------------------- /model/mesh/cube_8/cube_8.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 25 206 46 3 | -------------------------------------------------------------------------------- /model/mesh/cube_8/cube_8.node: -------------------------------------------------------------------------------- 1 | 285 2 | 0 0.25 0.25 0.25 3 | 1 0.375 0.25 0.25 4 | 2 0.5 0.25 0.25 5 | 3 0.625 0.25 0.25 6 | 4 0.75 0.25 0.25 7 | 5 0.25 0.375 0.25 8 | 6 0.375 0.375 0.25 9 | 7 0.5 0.375 0.25 10 | 8 0.625 0.375 0.25 11 | 9 0.75 0.375 0.25 12 | 10 0.25 0.5 0.25 13 | 11 0.375 0.5 0.25 14 | 12 0.5 0.5 0.25 15 | 13 0.625 0.5 0.25 16 | 14 0.75 0.5 0.25 17 | 15 0.25 0.625 0.25 18 | 16 0.375 0.625 0.25 19 | 17 0.5 0.625 0.25 20 | 18 0.625 0.625 0.25 21 | 19 0.75 0.625 0.25 22 | 20 0.25 0.75 0.25 23 | 21 0.375 0.75 0.25 24 | 22 0.5 0.75 0.25 25 | 23 0.625 0.75 0.25 26 | 24 0.75 0.75 0.25 27 | 25 0.3125 0.3125 0.3125 28 | 26 0.4375 0.3125 0.3125 29 | 27 0.5625 0.3125 0.3125 30 | 28 0.6875 0.3125 0.3125 31 | 29 0.3125 0.4375 0.3125 32 | 30 0.4375 0.4375 0.3125 33 | 31 0.5625 0.4375 0.3125 34 | 32 0.6875 0.4375 0.3125 35 | 33 0.3125 0.5625 0.3125 36 | 34 0.4375 0.5625 0.3125 37 | 35 0.5625 0.5625 0.3125 38 | 36 0.6875 0.5625 0.3125 39 | 37 0.3125 0.6875 0.3125 40 | 38 0.4375 0.6875 0.3125 41 | 39 0.5625 0.6875 0.3125 42 | 40 0.6875 0.6875 0.3125 43 | 41 0.25 0.25 0.375 44 | 42 0.375 0.25 0.375 45 | 43 0.5 0.25 0.375 46 | 44 0.625 0.25 0.375 47 | 45 0.75 0.25 0.375 48 | 46 0.25 0.375 0.375 49 | 47 0.375 0.375 0.375 50 | 48 0.5 0.375 0.375 51 | 49 0.625 0.375 0.375 52 | 50 0.75 0.375 0.375 53 | 51 0.25 0.5 0.375 54 | 52 0.375 0.5 0.375 55 | 53 0.5 0.5 0.375 56 | 54 0.625 0.5 0.375 57 | 55 0.75 0.5 0.375 58 | 56 0.25 0.625 0.375 59 | 57 0.375 0.625 0.375 60 | 58 0.5 0.625 0.375 61 | 59 0.625 0.625 0.375 62 | 60 0.75 0.625 0.375 63 | 61 0.25 0.75 0.375 64 | 62 0.375 0.75 0.375 65 | 63 0.5 0.75 0.375 66 | 64 0.625 0.75 0.375 67 | 65 0.75 0.75 0.375 68 | 66 0.3125 0.3125 0.4375 69 | 67 0.4375 0.3125 0.4375 70 | 68 0.5625 0.3125 0.4375 71 | 69 0.6875 0.3125 0.4375 72 | 70 0.3125 0.4375 0.4375 73 | 71 0.4375 0.4375 0.4375 74 | 72 0.5625 0.4375 0.4375 75 | 73 0.6875 0.4375 0.4375 76 | 74 0.3125 0.5625 0.4375 77 | 75 0.4375 0.5625 0.4375 78 | 76 0.5625 0.5625 0.4375 79 | 77 0.6875 0.5625 0.4375 80 | 78 0.3125 0.6875 0.4375 81 | 79 0.4375 0.6875 0.4375 82 | 80 0.5625 0.6875 0.4375 83 | 81 0.6875 0.6875 0.4375 84 | 82 0.25 0.25 0.5 85 | 83 0.375 0.25 0.5 86 | 84 0.5 0.25 0.5 87 | 85 0.625 0.25 0.5 88 | 86 0.75 0.25 0.5 89 | 87 0.25 0.375 0.5 90 | 88 0.375 0.375 0.5 91 | 89 0.5 0.375 0.5 92 | 90 0.625 0.375 0.5 93 | 91 0.75 0.375 0.5 94 | 92 0.25 0.5 0.5 95 | 93 0.375 0.5 0.5 96 | 94 0.5 0.5 0.5 97 | 95 0.625 0.5 0.5 98 | 96 0.75 0.5 0.5 99 | 97 0.25 0.625 0.5 100 | 98 0.375 0.625 0.5 101 | 99 0.5 0.625 0.5 102 | 100 0.625 0.625 0.5 103 | 101 0.75 0.625 0.5 104 | 102 0.25 0.75 0.5 105 | 103 0.375 0.75 0.5 106 | 104 0.5 0.75 0.5 107 | 105 0.625 0.75 0.5 108 | 106 0.75 0.75 0.5 109 | 107 0.3125 0.3125 0.5625 110 | 108 0.4375 0.3125 0.5625 111 | 109 0.5625 0.3125 0.5625 112 | 110 0.6875 0.3125 0.5625 113 | 111 0.3125 0.4375 0.5625 114 | 112 0.4375 0.4375 0.5625 115 | 113 0.5625 0.4375 0.5625 116 | 114 0.6875 0.4375 0.5625 117 | 115 0.3125 0.5625 0.5625 118 | 116 0.4375 0.5625 0.5625 119 | 117 0.5625 0.5625 0.5625 120 | 118 0.6875 0.5625 0.5625 121 | 119 0.3125 0.6875 0.5625 122 | 120 0.4375 0.6875 0.5625 123 | 121 0.5625 0.6875 0.5625 124 | 122 0.6875 0.6875 0.5625 125 | 123 0.25 0.25 0.625 126 | 124 0.375 0.25 0.625 127 | 125 0.5 0.25 0.625 128 | 126 0.625 0.25 0.625 129 | 127 0.75 0.25 0.625 130 | 128 0.25 0.375 0.625 131 | 129 0.375 0.375 0.625 132 | 130 0.5 0.375 0.625 133 | 131 0.625 0.375 0.625 134 | 132 0.75 0.375 0.625 135 | 133 0.25 0.5 0.625 136 | 134 0.375 0.5 0.625 137 | 135 0.5 0.5 0.625 138 | 136 0.625 0.5 0.625 139 | 137 0.75 0.5 0.625 140 | 138 0.25 0.625 0.625 141 | 139 0.375 0.625 0.625 142 | 140 0.5 0.625 0.625 143 | 141 0.625 0.625 0.625 144 | 142 0.75 0.625 0.625 145 | 143 0.25 0.75 0.625 146 | 144 0.375 0.75 0.625 147 | 145 0.5 0.75 0.625 148 | 146 0.625 0.75 0.625 149 | 147 0.75 0.75 0.625 150 | 148 0.3125 0.3125 0.6875 151 | 149 0.4375 0.3125 0.6875 152 | 150 0.5625 0.3125 0.6875 153 | 151 0.6875 0.3125 0.6875 154 | 152 0.3125 0.4375 0.6875 155 | 153 0.4375 0.4375 0.6875 156 | 154 0.5625 0.4375 0.6875 157 | 155 0.6875 0.4375 0.6875 158 | 156 0.3125 0.5625 0.6875 159 | 157 0.4375 0.5625 0.6875 160 | 158 0.5625 0.5625 0.6875 161 | 159 0.6875 0.5625 0.6875 162 | 160 0.3125 0.6875 0.6875 163 | 161 0.4375 0.6875 0.6875 164 | 162 0.5625 0.6875 0.6875 165 | 163 0.6875 0.6875 0.6875 166 | 164 0.25 0.25 0.75 167 | 165 0.375 0.25 0.75 168 | 166 0.5 0.25 0.75 169 | 167 0.625 0.25 0.75 170 | 168 0.75 0.25 0.75 171 | 169 0.25 0.375 0.75 172 | 170 0.375 0.375 0.75 173 | 171 0.5 0.375 0.75 174 | 172 0.625 0.375 0.75 175 | 173 0.75 0.375 0.75 176 | 174 0.25 0.5 0.75 177 | 175 0.375 0.5 0.75 178 | 176 0.5 0.5 0.75 179 | 177 0.625 0.5 0.75 180 | 178 0.75 0.5 0.75 181 | 179 0.25 0.625 0.75 182 | 180 0.375 0.625 0.75 183 | 181 0.5 0.625 0.75 184 | 182 0.625 0.625 0.75 185 | 183 0.75 0.625 0.75 186 | 184 0.25 0.75 0.75 187 | 185 0.375 0.75 0.75 188 | 186 0.5 0.75 0.75 189 | 187 0.625 0.75 0.75 190 | 188 0.75 0.75 0.75 191 | 189 0.75 0.6875 0.6875 192 | 190 0.6875 0.75 0.6875 193 | 191 0.6875 0.6875 0.75 194 | 192 0.3125 0.75 0.6875 195 | 193 0.4375 0.75 0.6875 196 | 194 0.5625 0.75 0.6875 197 | 195 0.3125 0.3125 0.75 198 | 196 0.4375 0.3125 0.75 199 | 197 0.3125 0.4375 0.75 200 | 198 0.6875 0.4375 0.75 201 | 199 0.5625 0.3125 0.75 202 | 200 0.6875 0.3125 0.75 203 | 201 0.4375 0.4375 0.75 204 | 202 0.5625 0.4375 0.75 205 | 203 0.3125 0.5625 0.75 206 | 204 0.3125 0.3125 0.25 207 | 205 0.3125 0.25 0.3125 208 | 206 0.25 0.3125 0.3125 209 | 207 0.5625 0.3125 0.25 210 | 208 0.6875 0.3125 0.25 211 | 209 0.4375 0.5625 0.25 212 | 210 0.4375 0.3125 0.25 213 | 211 0.5625 0.4375 0.25 214 | 212 0.6875 0.4375 0.25 215 | 213 0.3125 0.4375 0.25 216 | 214 0.4375 0.4375 0.25 217 | 215 0.5625 0.5625 0.25 218 | 216 0.6875 0.5625 0.25 219 | 217 0.3125 0.5625 0.25 220 | 218 0.5625 0.6875 0.25 221 | 219 0.6875 0.6875 0.25 222 | 220 0.3125 0.75 0.3125 223 | 221 0.3125 0.6875 0.25 224 | 222 0.4375 0.6875 0.25 225 | 223 0.4375 0.25 0.3125 226 | 224 0.5625 0.25 0.3125 227 | 225 0.6875 0.25 0.3125 228 | 226 0.25 0.4375 0.3125 229 | 227 0.3125 0.25 0.4375 230 | 228 0.25 0.3125 0.4375 231 | 229 0.25 0.5625 0.3125 232 | 230 0.75 0.3125 0.3125 233 | 231 0.25 0.6875 0.3125 234 | 232 0.75 0.4375 0.3125 235 | 233 0.4375 0.75 0.3125 236 | 234 0.75 0.5625 0.3125 237 | 235 0.5625 0.75 0.3125 238 | 236 0.75 0.6875 0.3125 239 | 237 0.6875 0.75 0.3125 240 | 238 0.3125 0.75 0.4375 241 | 239 0.6875 0.25 0.4375 242 | 240 0.4375 0.25 0.4375 243 | 241 0.5625 0.25 0.4375 244 | 242 0.25 0.4375 0.4375 245 | 243 0.3125 0.25 0.5625 246 | 244 0.25 0.3125 0.5625 247 | 245 0.25 0.5625 0.4375 248 | 246 0.75 0.3125 0.4375 249 | 247 0.25 0.6875 0.4375 250 | 248 0.75 0.4375 0.4375 251 | 249 0.4375 0.75 0.4375 252 | 250 0.75 0.5625 0.4375 253 | 251 0.5625 0.75 0.4375 254 | 252 0.75 0.6875 0.4375 255 | 253 0.6875 0.75 0.4375 256 | 254 0.3125 0.75 0.5625 257 | 255 0.6875 0.25 0.5625 258 | 256 0.4375 0.25 0.5625 259 | 257 0.5625 0.25 0.5625 260 | 258 0.25 0.4375 0.5625 261 | 259 0.3125 0.25 0.6875 262 | 260 0.25 0.3125 0.6875 263 | 261 0.25 0.5625 0.5625 264 | 262 0.75 0.3125 0.5625 265 | 263 0.25 0.6875 0.5625 266 | 264 0.75 0.4375 0.5625 267 | 265 0.4375 0.75 0.5625 268 | 266 0.75 0.5625 0.5625 269 | 267 0.5625 0.75 0.5625 270 | 268 0.75 0.6875 0.5625 271 | 269 0.6875 0.75 0.5625 272 | 270 0.6875 0.25 0.6875 273 | 271 0.4375 0.25 0.6875 274 | 272 0.5625 0.25 0.6875 275 | 273 0.25 0.4375 0.6875 276 | 274 0.75 0.3125 0.6875 277 | 275 0.75 0.4375 0.6875 278 | 276 0.25 0.5625 0.6875 279 | 277 0.4375 0.5625 0.75 280 | 278 0.5625 0.5625 0.75 281 | 279 0.75 0.5625 0.6875 282 | 280 0.6875 0.5625 0.75 283 | 281 0.5625 0.6875 0.75 284 | 282 0.25 0.6875 0.6875 285 | 283 0.3125 0.6875 0.75 286 | 284 0.4375 0.6875 0.75 287 | -------------------------------------------------------------------------------- /model/mesh/hole/hole.edge: -------------------------------------------------------------------------------- 1 | 126 2 | 0 0 1 3 | 1 1 2 4 | 2 2 0 5 | 3 0 3 6 | 4 3 4 7 | 5 4 0 8 | 6 0 5 9 | 7 5 3 10 | 8 4 6 11 | 9 6 0 12 | 10 0 7 13 | 11 7 1 14 | 12 6 7 15 | 13 2 5 16 | 14 8 9 17 | 15 9 10 18 | 16 10 8 19 | 17 10 11 20 | 18 11 8 21 | 19 11 12 22 | 20 12 8 23 | 21 8 13 24 | 22 13 9 25 | 23 8 14 26 | 24 14 13 27 | 25 12 15 28 | 26 15 8 29 | 27 15 14 30 | 28 16 17 31 | 29 17 6 32 | 30 6 16 33 | 31 16 18 34 | 32 18 19 35 | 33 19 16 36 | 34 19 17 37 | 35 16 15 38 | 36 15 18 39 | 37 4 16 40 | 38 4 14 41 | 39 14 16 42 | 40 20 5 43 | 41 5 21 44 | 42 21 20 45 | 43 20 22 46 | 44 22 23 47 | 45 23 20 48 | 46 20 9 49 | 47 13 20 50 | 48 20 3 51 | 49 13 3 52 | 50 21 22 53 | 51 23 9 54 | 52 2 24 55 | 53 24 25 56 | 54 25 2 57 | 55 1 24 58 | 56 25 26 59 | 57 26 2 60 | 58 26 5 61 | 59 24 27 62 | 60 27 28 63 | 61 28 24 64 | 62 28 25 65 | 63 24 7 66 | 64 7 27 67 | 65 28 26 68 | 66 27 6 69 | 67 6 29 70 | 68 29 27 71 | 69 29 28 72 | 70 26 21 73 | 71 28 30 74 | 72 30 26 75 | 73 26 31 76 | 74 31 21 77 | 75 30 31 78 | 76 31 32 79 | 77 32 21 80 | 78 32 22 81 | 79 29 33 82 | 80 33 28 83 | 81 28 34 84 | 82 34 30 85 | 83 33 34 86 | 84 30 35 87 | 85 35 32 88 | 86 32 30 89 | 87 30 36 90 | 88 36 35 91 | 89 34 36 92 | 90 32 23 93 | 91 35 23 94 | 92 17 29 95 | 93 17 37 96 | 94 37 29 97 | 95 37 33 98 | 96 33 38 99 | 97 38 39 100 | 98 39 33 101 | 99 39 40 102 | 100 40 33 103 | 101 37 38 104 | 102 40 34 105 | 103 3 14 106 | 104 36 23 107 | 105 36 9 108 | 106 9 41 109 | 107 41 10 110 | 108 36 41 111 | 109 34 41 112 | 110 34 42 113 | 111 42 43 114 | 112 43 34 115 | 113 43 41 116 | 114 40 42 117 | 115 43 11 118 | 116 10 43 119 | 117 43 12 120 | 118 42 12 121 | 119 40 12 122 | 120 40 15 123 | 121 39 18 124 | 122 18 40 125 | 123 38 18 126 | 124 38 19 127 | 125 38 17 128 | -------------------------------------------------------------------------------- /model/mesh/hole/hole.ele: -------------------------------------------------------------------------------- 1 | 79 2 | 0 5 0 12 8 3 | 1 6 0 12 5 4 | 2 0 6 4 5 5 | 3 18 39 2 38 6 | 4 23 27 1 29 7 | 5 0 4 7 5 8 | 6 10 3 9 11 9 | 7 12 19 43 0 10 | 8 22 3 20 15 11 | 9 21 3 14 15 12 | 10 3 15 16 14 13 | 11 20 3 21 15 14 | 12 14 12 9 19 15 | 13 43 12 17 18 16 | 14 0 9 12 19 17 | 15 9 0 11 19 18 | 16 28 3 23 24 19 | 17 9 10 16 3 20 | 18 23 27 28 1 21 | 19 9 3 16 14 22 | 20 39 33 2 38 23 | 21 3 19 9 11 24 | 22 14 19 9 3 25 | 23 9 0 12 6 26 | 24 4 9 6 0 27 | 25 30 1 32 31 28 | 26 2 43 17 18 29 | 27 24 25 1 28 30 | 28 36 17 2 42 31 | 29 28 3 14 21 32 | 30 35 1 26 29 33 | 31 28 14 24 25 34 | 32 39 33 41 2 35 | 33 19 14 24 3 36 | 34 0 42 43 17 37 | 35 35 1 30 26 38 | 36 28 23 1 24 39 | 37 10 3 15 16 40 | 38 22 3 15 10 41 | 39 20 28 21 3 42 | 40 8 42 0 17 43 | 41 3 28 14 24 44 | 42 37 19 43 12 45 | 43 13 5 8 0 46 | 44 12 14 24 19 47 | 45 25 27 1 28 48 | 46 31 26 1 25 49 | 47 30 26 1 31 50 | 48 25 26 1 27 51 | 49 32 33 38 2 52 | 50 24 25 37 1 53 | 51 25 12 24 37 54 | 52 24 19 37 12 55 | 53 41 39 2 36 56 | 54 13 5 0 7 57 | 55 34 1 32 30 58 | 56 33 2 32 34 59 | 57 36 17 40 2 60 | 58 1 26 29 27 61 | 59 12 0 17 8 62 | 60 20 28 3 23 63 | 61 2 42 17 43 64 | 62 8 42 13 0 65 | 63 43 0 17 12 66 | 64 12 25 24 14 67 | 65 17 18 40 2 68 | 66 32 2 38 18 69 | 67 12 25 18 37 70 | 68 39 36 40 2 71 | 69 2 43 18 37 72 | 70 12 37 18 43 73 | 71 18 39 40 2 74 | 72 37 2 32 18 75 | 73 37 34 32 2 76 | 74 25 31 32 1 77 | 75 18 25 32 37 78 | 76 4 9 0 11 79 | 77 34 1 37 32 80 | 78 25 1 32 37 81 | -------------------------------------------------------------------------------- /model/mesh/hole/hole.face: -------------------------------------------------------------------------------- 1 | 84 2 | 0 0 1 2 3 | 1 0 3 4 4 | 2 0 5 3 5 | 3 0 4 6 6 | 4 0 7 1 7 | 5 0 6 7 8 | 6 0 2 5 9 | 7 8 9 10 10 | 8 8 10 11 11 | 9 8 11 12 12 | 10 8 13 9 13 | 11 8 14 13 14 | 12 8 12 15 15 | 13 8 15 14 16 | 14 16 17 6 17 | 15 16 18 19 18 | 16 16 19 17 19 | 17 16 15 18 20 | 18 16 6 4 21 | 19 16 4 14 22 | 20 16 14 15 23 | 21 20 5 21 24 | 22 20 22 23 25 | 23 20 9 13 26 | 24 20 3 5 27 | 25 20 13 3 28 | 26 20 21 22 29 | 27 20 23 9 30 | 28 2 24 25 31 | 29 2 1 24 32 | 30 2 25 26 33 | 31 2 26 5 34 | 32 24 27 28 35 | 33 24 28 25 36 | 34 24 7 27 37 | 35 24 1 7 38 | 36 25 28 26 39 | 37 27 6 29 40 | 38 27 29 28 41 | 39 27 7 6 42 | 40 26 21 5 43 | 41 26 28 30 44 | 42 26 31 21 45 | 43 26 30 31 46 | 44 21 31 32 47 | 45 21 32 22 48 | 46 28 29 33 49 | 47 28 34 30 50 | 48 28 33 34 51 | 49 30 35 32 52 | 50 30 32 31 53 | 51 30 36 35 54 | 52 30 34 36 55 | 53 32 23 22 56 | 54 32 35 23 57 | 55 29 6 17 58 | 56 29 17 37 59 | 57 29 37 33 60 | 58 33 38 39 61 | 59 33 39 40 62 | 60 33 37 38 63 | 61 33 40 34 64 | 62 3 14 4 65 | 63 3 13 14 66 | 64 23 35 36 67 | 65 23 36 9 68 | 66 9 41 10 69 | 67 9 36 41 70 | 68 34 41 36 71 | 69 34 42 43 72 | 70 34 43 41 73 | 71 34 40 42 74 | 72 43 11 10 75 | 73 43 12 11 76 | 74 43 42 12 77 | 75 43 10 41 78 | 76 12 42 40 79 | 77 12 40 15 80 | 78 40 39 18 81 | 79 40 18 15 82 | 80 18 39 38 83 | 81 18 38 19 84 | 82 17 19 38 85 | 83 17 38 37 86 | -------------------------------------------------------------------------------- /model/mesh/hole/hole.node: -------------------------------------------------------------------------------- 1 | 44 2 | 0 -0.5 0.5 -0.5 3 | 1 0.5 0.5 0.5 4 | 2 0.5 0.5 -0.5 5 | 3 -0.5 0.5 0.5 6 | 4 -1.0 0.5 -0.5 7 | 5 -1.0 -0.5 -1.0 8 | 6 -1.0 -0.5 -0.5 9 | 7 -1.0 0.5 -1.0 10 | 8 -0.5 -0.5 -1.0 11 | 9 -1.0 -0.5 -0.0 12 | 10 -1.0 0.5 0.5 13 | 11 -1.0 0.5 -0.0 14 | 12 -0.5 -0.5 -0.5 15 | 13 -0.5 0.5 -1.0 16 | 14 -0.5 -0.5 0.5 17 | 15 -1.0 -0.5 1.0 18 | 16 -1.0 -0.5 0.5 19 | 17 0.0 -0.5 -1.0 20 | 18 0.5 -0.5 -0.5 21 | 19 -0.5 0.5 -0.0 22 | 20 -0.5 0.5 1.0 23 | 21 -0.5 -0.5 1.0 24 | 22 -1.0 0.5 1.0 25 | 23 -0.0 0.5 1.0 26 | 24 -0.0 0.5 0.5 27 | 25 0.5 -0.5 0.5 28 | 26 1.0 -0.5 1.0 29 | 27 0.5 -0.5 1.0 30 | 28 -0.0 -0.5 1.0 31 | 29 0.5 0.5 1.0 32 | 30 1.0 0.5 0.5 33 | 31 1.0 -0.5 0.5 34 | 32 1.0 -0.5 -0.0 35 | 33 1.0 0.5 -0.5 36 | 34 1.0 0.5 -0.0 37 | 35 1.0 0.5 1.0 38 | 36 0.5 0.5 -1.0 39 | 37 0.5 0.5 -0.0 40 | 38 1.0 -0.5 -0.5 41 | 39 1.0 -0.5 -1.0 42 | 40 0.5 -0.5 -1.0 43 | 41 1.0 0.5 -1.0 44 | 42 0.0 0.5 -1.0 45 | 43 -0.0 0.5 -0.5 46 | -------------------------------------------------------------------------------- /model/mesh/internal_edges/internal_edges.edge: -------------------------------------------------------------------------------- 1 | 39 2 | 0 0 1 3 | 1 1 2 4 | 2 2 0 5 | 3 0 3 6 | 4 3 1 7 | 5 0 4 8 | 6 4 5 9 | 7 5 0 10 | 8 0 6 11 | 9 6 4 12 | 10 5 3 13 | 11 2 6 14 | 12 6 5 15 | 13 6 7 16 | 14 7 5 17 | 15 7 8 18 | 16 8 5 19 | 17 8 3 20 | 18 6 9 21 | 19 9 10 22 | 20 10 6 23 | 21 10 7 24 | 22 2 11 25 | 23 11 6 26 | 24 11 9 27 | 25 9 7 28 | 26 9 12 29 | 27 12 7 30 | 28 12 8 31 | 29 9 13 32 | 30 13 12 33 | 31 11 13 34 | 32 13 14 35 | 33 14 12 36 | 34 11 14 37 | 35 12 3 38 | 36 14 3 39 | 37 14 1 40 | 38 14 2 41 | -------------------------------------------------------------------------------- /model/mesh/internal_edges/internal_edges.ele: -------------------------------------------------------------------------------- 1 | 20 2 | 0 8 6 5 14 3 | 1 3 0 2 14 4 | 2 11 10 9 12 5 | 3 0 10 11 12 6 | 4 6 3 5 14 7 | 5 9 11 12 14 8 | 6 8 7 6 13 9 | 7 6 8 13 14 10 | 8 7 8 9 13 11 | 9 0 1 3 2 12 | 10 8 9 13 14 13 | 11 11 0 12 14 14 | 12 3 6 5 4 15 | 13 3 2 5 14 16 | 14 12 13 9 14 17 | 15 13 12 3 14 18 | 16 8 11 9 14 19 | 17 2 0 11 14 20 | 18 13 3 6 14 21 | 19 12 0 3 14 22 | -------------------------------------------------------------------------------- /model/mesh/internal_edges/internal_edges.face: -------------------------------------------------------------------------------- 1 | 26 2 | 0 0 1 2 3 | 1 0 3 1 4 | 2 0 4 5 5 | 3 0 6 4 6 | 4 0 5 3 7 | 5 0 2 6 8 | 6 4 6 5 9 | 7 5 6 7 10 | 8 5 7 8 11 | 9 5 8 3 12 | 10 6 9 10 13 | 11 6 10 7 14 | 12 6 2 11 15 | 13 6 11 9 16 | 14 10 9 7 17 | 15 7 9 12 18 | 16 7 12 8 19 | 17 9 13 12 20 | 18 9 11 13 21 | 19 13 14 12 22 | 20 13 11 14 23 | 21 12 3 8 24 | 22 12 14 3 25 | 23 14 1 3 26 | 24 14 2 1 27 | 25 14 11 2 28 | -------------------------------------------------------------------------------- /model/mesh/internal_edges/internal_edges.node: -------------------------------------------------------------------------------- 1 | 15 2 | 0 -1.0 0.5 0.0 3 | 1 -1.0 0.5 -1.0 4 | 2 -1.0 -0.5 -1.0 5 | 3 0.0 0.5 -1.0 6 | 4 1.0 0.5 -1.0 7 | 5 1.0 -0.5 -1.0 8 | 6 1.0 0.5 0.0 9 | 7 1.0 0.5 1.0 10 | 8 1.0 -0.5 1.0 11 | 9 0.0 0.5 1.0 12 | 10 -1.0 0.5 1.0 13 | 11 -1.0 -0.5 1.0 14 | 12 -0.5 0.5 0.5 15 | 13 0.5 0.5 0.5 16 | 14 0.0 -0.5 0.0 17 | -------------------------------------------------------------------------------- /model/mesh/mat150x150t40_new/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/mat150x150t40_new/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/mat150x150t40_new/mat150x150t40_new.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 1 2 3 -------------------------------------------------------------------------------- /model/mesh/rod300x33/is_dirichlet.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/model/mesh/rod300x33/is_dirichlet.npy -------------------------------------------------------------------------------- /model/mesh/rod300x33/rod300x33.face: -------------------------------------------------------------------------------- 1 | 1 2 | 0 1 2 3 -------------------------------------------------------------------------------- /model/mesh/spike/spike.edge: -------------------------------------------------------------------------------- 1 | 9 2 | 0 0 1 3 | 1 1 2 4 | 2 2 0 5 | 3 2 3 6 | 4 3 0 7 | 5 0 4 8 | 6 4 1 9 | 7 3 4 10 | 8 1 3 11 | -------------------------------------------------------------------------------- /model/mesh/spike/spike.ele: -------------------------------------------------------------------------------- 1 | 2 2 | 0 0 3 1 4 3 | 1 0 3 2 1 4 | -------------------------------------------------------------------------------- /model/mesh/spike/spike.face: -------------------------------------------------------------------------------- 1 | 6 2 | 0 0 1 2 3 | 1 0 2 3 4 | 2 0 4 1 5 | 3 0 3 4 6 | 4 3 2 1 7 | 5 3 1 4 8 | -------------------------------------------------------------------------------- /model/mesh/spike/spike.node: -------------------------------------------------------------------------------- 1 | 5 2 | 0 0.5 0.0 -0.5 3 | 1 0.0 3.0 0.0 4 | 2 0.5 0.0 0.5 5 | 3 -0.5 0.0 0.5 6 | 4 -0.5 0.0 -0.5 7 | -------------------------------------------------------------------------------- /model/mesh/tet/tet.ele: -------------------------------------------------------------------------------- 1 | 1 2 | 0 0 3 2 1 3 | -------------------------------------------------------------------------------- /model/mesh/tet/tet.node: -------------------------------------------------------------------------------- 1 | 4 2 | 0 0.0 0.0 0.0 3 | 1 1.0 0.0 0.0 4 | 2 0.0 0.0 1.0 5 | 3 0.0 1.0 0.0 6 | -------------------------------------------------------------------------------- /model/mesh/wedge/wedge.edge: -------------------------------------------------------------------------------- 1 | 12 2 | 0 0 1 3 | 1 1 2 4 | 2 2 0 5 | 3 0 3 6 | 4 3 4 7 | 5 4 0 8 | 6 2 3 9 | 7 0 5 10 | 8 5 1 11 | 9 4 5 12 | 10 4 2 13 | 11 1 4 14 | -------------------------------------------------------------------------------- /model/mesh/wedge/wedge.ele: -------------------------------------------------------------------------------- 1 | 3 2 | 0 5 1 0 3 3 | 1 1 0 3 4 4 | 2 5 1 2 0 5 | -------------------------------------------------------------------------------- /model/mesh/wedge/wedge.face: -------------------------------------------------------------------------------- 1 | 8 2 | 0 0 1 2 3 | 1 0 3 4 4 | 2 0 2 3 5 | 3 0 5 1 6 | 4 0 4 5 7 | 5 4 2 1 8 | 6 4 3 2 9 | 7 4 1 5 10 | -------------------------------------------------------------------------------- /model/mesh/wedge/wedge.node: -------------------------------------------------------------------------------- 1 | 6 2 | 0 0.0 3.0 1.0 3 | 1 -0.5 0.0 -1.0 4 | 2 -0.5 0.0 1.0 5 | 3 0.5 0.0 -1.0 6 | 4 0.0 3.0 -1.0 7 | 5 0.5 0.0 1.0 8 | -------------------------------------------------------------------------------- /others/Paper介绍.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/others/Paper介绍.pdf -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | taichi 2 | meshtaichi-patcher 3 | scipy 4 | imageio -------------------------------------------------------------------------------- /siggraphconferencepapers24-96_camera.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xingbaji/PNCG_IPC/25f4259db8144f107a08fd6bf0222dadb0b3788f/siggraphconferencepapers24-96_camera.pdf -------------------------------------------------------------------------------- /util/logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | 4 | 5 | # https://stackoverflow.com/questions/24204898/python-output-on-both-console-and-file 6 | # https://stackoverflow.com/questions/46971566/python-to-handle-color-to-terminal-and-also-in-file 7 | class Logger: 8 | def __init__(self, filename): 9 | self.out_file = open(filename, "w") 10 | self.old_stdout = sys.stdout 11 | #this object will take over `stdout`'s job 12 | sys.stdout = self 13 | 14 | #executed when the user does a `print` 15 | def write(self, text): 16 | self.old_stdout.write(text) 17 | self.out_file.write(re.sub('\033\\[\d+m', '', text)) 18 | 19 | #executed when `with` block begins 20 | def __enter__(self): 21 | return self 22 | 23 | #executed when `with` block ends 24 | def __exit__(self, type, value, traceback): 25 | #we don't want to log anymore. Restore the original stdout object. 26 | sys.stdout = self.old_stdout 27 | -------------------------------------------------------------------------------- /util/timer.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | 3 | stack = [] 4 | index = dict() 5 | flags = [] 6 | levels = [] 7 | timings = [] 8 | 9 | 10 | class Timer(object): 11 | def __init__(self, description): 12 | self.description = description 13 | 14 | def __enter__(self): 15 | stack.append(self.description) 16 | if self.description not in index: 17 | index[self.description] = len(flags) 18 | flags.append(self.description) 19 | levels.append(len(stack)) 20 | timings.append(0.0) 21 | id = index[self.description] 22 | timings[id] -= time() 23 | 24 | def __exit__(self, type, value, traceback): 25 | stack.pop() 26 | id = index[self.description] 27 | timings[id] += time() 28 | 29 | 30 | def Timer_Print(): 31 | total = 0.0 32 | for l, t in zip(levels, timings): 33 | if l == 1: 34 | total += t 35 | Timer_Print.cnt += 1 36 | if Timer_Print.cnt == 2: 37 | Timer_Print.cmp -= total 38 | 39 | for f, l, t in zip(flags, levels, timings): 40 | print(' ' * l, end='') 41 | avg_t = t / max(1, Timer_Print.cnt - 1) 42 | avg_p = t / total 43 | tot_t = t 44 | print('{0:s}: \033[92m{1:.4f}s, {2:.1%}\033[0m \033[33m(All: {3:.2f}s)\033[0m'.format(f, avg_t, avg_p, tot_t)) 45 | print(' Compile Time: \033[92m{0:.2f}s\033[0m'.format(Timer_Print.cmp)) 46 | print('') 47 | 48 | if Timer_Print.cnt == 1: 49 | Timer_Print.cmp = total 50 | for i in range(len(timings)): 51 | timings[i] = 0.0 52 | 53 | 54 | Timer_Print.cnt = 0 55 | Timer_Print.cmp = 0.0 56 | --------------------------------------------------------------------------------