├── .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 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
--------------------------------------------------------------------------------