warp-lang 1.5.1__py3-none-manylinux2014_x86_64.whl → 1.6.1__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of warp-lang might be problematic. Click here for more details.
- warp/__init__.py +5 -0
- warp/autograd.py +414 -191
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +40 -12
- warp/build_dll.py +13 -6
- warp/builtins.py +1077 -481
- warp/codegen.py +250 -122
- warp/config.py +65 -21
- warp/context.py +500 -149
- warp/examples/assets/square_cloth.usd +0 -0
- warp/examples/benchmarks/benchmark_gemm.py +27 -18
- warp/examples/benchmarks/benchmark_interop_paddle.py +3 -3
- warp/examples/benchmarks/benchmark_interop_torch.py +3 -3
- warp/examples/core/example_marching_cubes.py +1 -1
- warp/examples/core/example_mesh.py +1 -1
- warp/examples/core/example_torch.py +18 -34
- warp/examples/core/example_wave.py +1 -1
- warp/examples/fem/example_apic_fluid.py +1 -0
- warp/examples/fem/example_mixed_elasticity.py +1 -1
- warp/examples/optim/example_bounce.py +1 -1
- warp/examples/optim/example_cloth_throw.py +1 -1
- warp/examples/optim/example_diffray.py +4 -15
- warp/examples/optim/example_drone.py +1 -1
- warp/examples/optim/example_softbody_properties.py +392 -0
- warp/examples/optim/example_trajectory.py +1 -3
- warp/examples/optim/example_walker.py +5 -0
- warp/examples/sim/example_cartpole.py +0 -2
- warp/examples/sim/example_cloth_self_contact.py +314 -0
- warp/examples/sim/example_granular_collision_sdf.py +4 -5
- warp/examples/sim/example_jacobian_ik.py +0 -2
- warp/examples/sim/example_quadruped.py +5 -2
- warp/examples/tile/example_tile_cholesky.py +79 -0
- warp/examples/tile/example_tile_convolution.py +2 -2
- warp/examples/tile/example_tile_fft.py +2 -2
- warp/examples/tile/example_tile_filtering.py +3 -3
- warp/examples/tile/example_tile_matmul.py +4 -4
- warp/examples/tile/example_tile_mlp.py +12 -12
- warp/examples/tile/example_tile_nbody.py +191 -0
- warp/examples/tile/example_tile_walker.py +319 -0
- warp/math.py +147 -0
- warp/native/array.h +12 -0
- warp/native/builtin.h +0 -1
- warp/native/bvh.cpp +149 -70
- warp/native/bvh.cu +287 -68
- warp/native/bvh.h +195 -85
- warp/native/clang/clang.cpp +6 -2
- warp/native/crt.h +1 -0
- warp/native/cuda_util.cpp +35 -0
- warp/native/cuda_util.h +5 -0
- warp/native/exports.h +40 -40
- warp/native/intersect.h +17 -0
- warp/native/mat.h +57 -3
- warp/native/mathdx.cpp +19 -0
- warp/native/mesh.cpp +25 -8
- warp/native/mesh.cu +153 -101
- warp/native/mesh.h +482 -403
- warp/native/quat.h +40 -0
- warp/native/solid_angle.h +7 -0
- warp/native/sort.cpp +85 -0
- warp/native/sort.cu +34 -0
- warp/native/sort.h +3 -1
- warp/native/spatial.h +11 -0
- warp/native/tile.h +1189 -664
- warp/native/tile_reduce.h +8 -6
- warp/native/vec.h +41 -0
- warp/native/warp.cpp +8 -1
- warp/native/warp.cu +263 -40
- warp/native/warp.h +19 -5
- warp/optim/linear.py +22 -4
- warp/render/render_opengl.py +132 -59
- warp/render/render_usd.py +10 -2
- warp/sim/__init__.py +6 -1
- warp/sim/collide.py +289 -32
- warp/sim/import_urdf.py +20 -5
- warp/sim/integrator_euler.py +25 -7
- warp/sim/integrator_featherstone.py +147 -35
- warp/sim/integrator_vbd.py +842 -40
- warp/sim/model.py +173 -112
- warp/sim/render.py +2 -2
- warp/stubs.py +249 -116
- warp/tape.py +28 -30
- warp/tests/aux_test_module_unload.py +15 -0
- warp/tests/{test_sim_grad.py → flaky_test_sim_grad.py} +104 -63
- warp/tests/test_array.py +100 -0
- warp/tests/test_assert.py +242 -0
- warp/tests/test_codegen.py +14 -61
- warp/tests/test_collision.py +8 -8
- warp/tests/test_examples.py +16 -1
- warp/tests/test_grad_debug.py +87 -2
- warp/tests/test_hash_grid.py +1 -1
- warp/tests/test_ipc.py +116 -0
- warp/tests/test_launch.py +77 -26
- warp/tests/test_mat.py +213 -168
- warp/tests/test_math.py +47 -1
- warp/tests/test_matmul.py +11 -7
- warp/tests/test_matmul_lite.py +4 -4
- warp/tests/test_mesh.py +84 -60
- warp/tests/test_mesh_query_aabb.py +165 -0
- warp/tests/test_mesh_query_point.py +328 -286
- warp/tests/test_mesh_query_ray.py +134 -121
- warp/tests/test_mlp.py +2 -2
- warp/tests/test_operators.py +43 -0
- warp/tests/test_overwrite.py +6 -5
- warp/tests/test_quat.py +77 -0
- warp/tests/test_reload.py +29 -0
- warp/tests/test_sim_grad_bounce_linear.py +204 -0
- warp/tests/test_static.py +16 -0
- warp/tests/test_tape.py +25 -0
- warp/tests/test_tile.py +134 -191
- warp/tests/test_tile_load.py +399 -0
- warp/tests/test_tile_mathdx.py +61 -8
- warp/tests/test_tile_mlp.py +17 -17
- warp/tests/test_tile_reduce.py +24 -18
- warp/tests/test_tile_shared_memory.py +66 -17
- warp/tests/test_tile_view.py +165 -0
- warp/tests/test_torch.py +35 -0
- warp/tests/test_utils.py +36 -24
- warp/tests/test_vec.py +110 -0
- warp/tests/unittest_suites.py +29 -4
- warp/tests/unittest_utils.py +30 -11
- warp/thirdparty/unittest_parallel.py +5 -2
- warp/types.py +419 -111
- warp/utils.py +9 -5
- {warp_lang-1.5.1.dist-info → warp_lang-1.6.1.dist-info}/METADATA +86 -45
- {warp_lang-1.5.1.dist-info → warp_lang-1.6.1.dist-info}/RECORD +129 -118
- {warp_lang-1.5.1.dist-info → warp_lang-1.6.1.dist-info}/WHEEL +1 -1
- warp/examples/benchmarks/benchmark_tile.py +0 -179
- warp/native/tile_gemm.h +0 -341
- {warp_lang-1.5.1.dist-info → warp_lang-1.6.1.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.5.1.dist-info → warp_lang-1.6.1.dist-info}/top_level.txt +0 -0
warp/sim/integrator_vbd.py
CHANGED
|
@@ -9,9 +9,31 @@ import numpy as np
|
|
|
9
9
|
import warp as wp
|
|
10
10
|
|
|
11
11
|
from ..types import float32, matrix
|
|
12
|
+
from .collide import (
|
|
13
|
+
TriMeshCollisionDetector,
|
|
14
|
+
TriMeshCollisionInfo,
|
|
15
|
+
get_edge_colliding_edges,
|
|
16
|
+
get_edge_colliding_edges_count,
|
|
17
|
+
get_triangle_colliding_vertices,
|
|
18
|
+
get_triangle_colliding_vertices_count,
|
|
19
|
+
get_vertex_colliding_triangles,
|
|
20
|
+
get_vertex_colliding_triangles_count,
|
|
21
|
+
triangle_closest_point,
|
|
22
|
+
)
|
|
12
23
|
from .integrator import Integrator
|
|
13
24
|
from .model import PARTICLE_FLAG_ACTIVE, Control, Model, ModelShapeMaterials, State
|
|
14
25
|
|
|
26
|
+
wp.set_module_options({"enable_backward": False})
|
|
27
|
+
|
|
28
|
+
VBD_DEBUG_PRINTING_OPTIONS = {
|
|
29
|
+
# "elasticity_force_hessian",
|
|
30
|
+
# "contact_force_hessian",
|
|
31
|
+
# "overall_force_hessian",
|
|
32
|
+
# "inertia_force_hessian",
|
|
33
|
+
# "connectivity",
|
|
34
|
+
# "contact_info",
|
|
35
|
+
}
|
|
36
|
+
|
|
15
37
|
|
|
16
38
|
class mat66(matrix(shape=(6, 6), dtype=float32)):
|
|
17
39
|
pass
|
|
@@ -54,23 +76,23 @@ class ForceElementAdjacencyInfo:
|
|
|
54
76
|
|
|
55
77
|
|
|
56
78
|
@wp.func
|
|
57
|
-
def get_vertex_num_adjacent_edges(vertex: wp.int32
|
|
79
|
+
def get_vertex_num_adjacent_edges(adjacency: ForceElementAdjacencyInfo, vertex: wp.int32):
|
|
58
80
|
return (adjacency.v_adj_edges_offsets[vertex + 1] - adjacency.v_adj_edges_offsets[vertex]) >> 1
|
|
59
81
|
|
|
60
82
|
|
|
61
83
|
@wp.func
|
|
62
|
-
def get_vertex_adjacent_edge_id_order(vertex: wp.int32, edge: wp.int32
|
|
84
|
+
def get_vertex_adjacent_edge_id_order(adjacency: ForceElementAdjacencyInfo, vertex: wp.int32, edge: wp.int32):
|
|
63
85
|
offset = adjacency.v_adj_edges_offsets[vertex]
|
|
64
86
|
return adjacency.v_adj_edges[offset + edge * 2], adjacency.v_adj_edges[offset + edge * 2 + 1]
|
|
65
87
|
|
|
66
88
|
|
|
67
89
|
@wp.func
|
|
68
|
-
def get_vertex_num_adjacent_faces(vertex: wp.int32
|
|
90
|
+
def get_vertex_num_adjacent_faces(adjacency: ForceElementAdjacencyInfo, vertex: wp.int32):
|
|
69
91
|
return (adjacency.v_adj_faces_offsets[vertex + 1] - adjacency.v_adj_faces_offsets[vertex]) >> 1
|
|
70
92
|
|
|
71
93
|
|
|
72
94
|
@wp.func
|
|
73
|
-
def get_vertex_adjacent_face_id_order(vertex: wp.int32, face: wp.int32
|
|
95
|
+
def get_vertex_adjacent_face_id_order(adjacency: ForceElementAdjacencyInfo, vertex: wp.int32, face: wp.int32):
|
|
74
96
|
offset = adjacency.v_adj_faces_offsets[vertex]
|
|
75
97
|
return adjacency.v_adj_faces[offset + face * 2], adjacency.v_adj_faces[offset + face * 2 + 1]
|
|
76
98
|
|
|
@@ -83,9 +105,9 @@ def _test_compute_force_element_adjacency(
|
|
|
83
105
|
):
|
|
84
106
|
wp.printf("num vertices: %d\n", adjacency.v_adj_edges_offsets.shape[0] - 1)
|
|
85
107
|
for vertex in range(adjacency.v_adj_edges_offsets.shape[0] - 1):
|
|
86
|
-
num_adj_edges = get_vertex_num_adjacent_edges(
|
|
108
|
+
num_adj_edges = get_vertex_num_adjacent_edges(adjacency, vertex)
|
|
87
109
|
for i_bd in range(num_adj_edges):
|
|
88
|
-
bd_id, v_order = get_vertex_adjacent_edge_id_order(vertex, i_bd
|
|
110
|
+
bd_id, v_order = get_vertex_adjacent_edge_id_order(adjacency, vertex, i_bd)
|
|
89
111
|
|
|
90
112
|
if edge_indices[bd_id, v_order] != vertex:
|
|
91
113
|
print("Error!!!")
|
|
@@ -93,10 +115,14 @@ def _test_compute_force_element_adjacency(
|
|
|
93
115
|
wp.printf("--iBd: %d | ", i_bd)
|
|
94
116
|
wp.printf("edge id: %d | v_order: %d\n", bd_id, v_order)
|
|
95
117
|
|
|
96
|
-
num_adj_faces = get_vertex_num_adjacent_faces(
|
|
118
|
+
num_adj_faces = get_vertex_num_adjacent_faces(adjacency, vertex)
|
|
97
119
|
|
|
98
120
|
for i_face in range(num_adj_faces):
|
|
99
|
-
face, v_order = get_vertex_adjacent_face_id_order(
|
|
121
|
+
face, v_order = get_vertex_adjacent_face_id_order(
|
|
122
|
+
adjacency,
|
|
123
|
+
vertex,
|
|
124
|
+
i_face,
|
|
125
|
+
)
|
|
100
126
|
|
|
101
127
|
if face_indices[face, v_order] != vertex:
|
|
102
128
|
print("Error!!!")
|
|
@@ -200,16 +226,6 @@ def evaluate_stvk_force_hessian(
|
|
|
200
226
|
F = calculate_triangle_deformation_gradient(face, tri_indices, pos, tri_pose)
|
|
201
227
|
G = green_strain(F)
|
|
202
228
|
|
|
203
|
-
# wp.printf("face: %d, \nF12:\n, %f %f\n, %f %f\n, %f %f\nG:\n%f %f\n, %f %f\n",
|
|
204
|
-
# face,
|
|
205
|
-
# F[0, 0], F[0, 1],
|
|
206
|
-
# F[1, 0], F[1, 1],
|
|
207
|
-
# F[2, 0], F[2, 1],
|
|
208
|
-
#
|
|
209
|
-
# G[0, 0], G[0, 1],
|
|
210
|
-
# G[1, 0], G[1, 1],
|
|
211
|
-
# )
|
|
212
|
-
|
|
213
229
|
S = 2.0 * mu * G + lmbd * (G[0, 0] + G[1, 1]) * wp.identity(n=2, dtype=float)
|
|
214
230
|
|
|
215
231
|
F12 = -area * F * S * wp.transpose(tri_pose)
|
|
@@ -323,8 +339,8 @@ def evaluate_stvk_force_hessian(
|
|
|
323
339
|
|
|
324
340
|
@wp.func
|
|
325
341
|
def evaluate_ground_contact_force_hessian(
|
|
326
|
-
|
|
327
|
-
|
|
342
|
+
particle_pos: wp.vec3,
|
|
343
|
+
particle_prev_pos: wp.vec3,
|
|
328
344
|
particle_radius: float,
|
|
329
345
|
ground_normal: wp.vec3,
|
|
330
346
|
ground_level: float,
|
|
@@ -333,14 +349,14 @@ def evaluate_ground_contact_force_hessian(
|
|
|
333
349
|
friction_epsilon: float,
|
|
334
350
|
dt: float,
|
|
335
351
|
):
|
|
336
|
-
penetration_depth = -(wp.dot(ground_normal,
|
|
352
|
+
penetration_depth = -(wp.dot(ground_normal, particle_pos) + ground_level - particle_radius)
|
|
337
353
|
|
|
338
354
|
if penetration_depth > 0:
|
|
339
355
|
ground_contact_force_norm = penetration_depth * soft_contact_ke
|
|
340
356
|
ground_contact_force = ground_normal * ground_contact_force_norm
|
|
341
357
|
ground_contact_hessian = soft_contact_ke * wp.outer(ground_normal, ground_normal)
|
|
342
358
|
|
|
343
|
-
dx =
|
|
359
|
+
dx = particle_pos - particle_prev_pos
|
|
344
360
|
|
|
345
361
|
# friction
|
|
346
362
|
e0, e1 = build_orthonormal_basis(ground_normal)
|
|
@@ -438,10 +454,221 @@ def evaluate_body_particle_contact(
|
|
|
438
454
|
return body_contact_force, body_contact_hessian
|
|
439
455
|
|
|
440
456
|
|
|
457
|
+
@wp.func
|
|
458
|
+
def evaluate_self_contact_force_norm(dis: float, collision_radius: float, k: float):
|
|
459
|
+
# Adjust distance and calculate penetration depth
|
|
460
|
+
|
|
461
|
+
penetration_depth = collision_radius - dis
|
|
462
|
+
|
|
463
|
+
# Initialize outputs
|
|
464
|
+
dEdD = wp.float32(0.0)
|
|
465
|
+
d2E_dDdD = wp.float32(0.0)
|
|
466
|
+
|
|
467
|
+
# C2 continuity calculation
|
|
468
|
+
tau = collision_radius * 0.5
|
|
469
|
+
if tau > dis > 1e-5:
|
|
470
|
+
k2 = 0.5 * tau * tau * k
|
|
471
|
+
dEdD = -k2 / dis
|
|
472
|
+
d2E_dDdD = k2 / (dis * dis)
|
|
473
|
+
else:
|
|
474
|
+
dEdD = -k * penetration_depth
|
|
475
|
+
d2E_dDdD = k
|
|
476
|
+
|
|
477
|
+
return dEdD, d2E_dDdD
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
@wp.func
|
|
481
|
+
def evaluate_edge_edge_contact(
|
|
482
|
+
v: int,
|
|
483
|
+
v_order: int,
|
|
484
|
+
e1: int,
|
|
485
|
+
e2: int,
|
|
486
|
+
pos: wp.array(dtype=wp.vec3),
|
|
487
|
+
pos_prev: wp.array(dtype=wp.vec3),
|
|
488
|
+
edge_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
489
|
+
collision_radius: float,
|
|
490
|
+
collision_stiffness: float,
|
|
491
|
+
friction_coefficient: float,
|
|
492
|
+
friction_epsilon: float,
|
|
493
|
+
dt: float,
|
|
494
|
+
edge_edge_parallel_epsilon: float,
|
|
495
|
+
):
|
|
496
|
+
r"""
|
|
497
|
+
Returns the edge-edge contact force and hessian, including the friction force.
|
|
498
|
+
Args:
|
|
499
|
+
v:
|
|
500
|
+
v_order: \in {0, 1, 2, 3}, 0, 1 is vertex 0, 1 of e1, 2,3 is vertex 0, 1 of e2
|
|
501
|
+
e0
|
|
502
|
+
e1
|
|
503
|
+
pos
|
|
504
|
+
edge_indices
|
|
505
|
+
collision_radius
|
|
506
|
+
collision_stiffness
|
|
507
|
+
dt
|
|
508
|
+
"""
|
|
509
|
+
e1_v1 = edge_indices[e1, 2]
|
|
510
|
+
e1_v2 = edge_indices[e1, 3]
|
|
511
|
+
|
|
512
|
+
e1_v1_pos = pos[e1_v1]
|
|
513
|
+
e1_v2_pos = pos[e1_v2]
|
|
514
|
+
|
|
515
|
+
e2_v1 = edge_indices[e2, 2]
|
|
516
|
+
e2_v2 = edge_indices[e2, 3]
|
|
517
|
+
|
|
518
|
+
e2_v1_pos = pos[e2_v1]
|
|
519
|
+
e2_v2_pos = pos[e2_v2]
|
|
520
|
+
|
|
521
|
+
st = wp.closest_point_edge_edge(e1_v1_pos, e1_v2_pos, e2_v1_pos, e2_v2_pos, edge_edge_parallel_epsilon)
|
|
522
|
+
s = st[0]
|
|
523
|
+
t = st[1]
|
|
524
|
+
e1_vec = e1_v2_pos - e1_v1_pos
|
|
525
|
+
e2_vec = e2_v2_pos - e2_v1_pos
|
|
526
|
+
c1 = e1_v1_pos + e1_vec * s
|
|
527
|
+
c2 = e2_v1_pos + e2_vec * t
|
|
528
|
+
|
|
529
|
+
# c1, c2, s, t = closest_point_edge_edge_2(e1_v1_pos, e1_v2_pos, e2_v1_pos, e2_v2_pos)
|
|
530
|
+
|
|
531
|
+
diff = c1 - c2
|
|
532
|
+
dis = st[2]
|
|
533
|
+
collision_normal = diff / dis
|
|
534
|
+
|
|
535
|
+
if dis < collision_radius:
|
|
536
|
+
bs = wp.vec4(1.0 - s, s, -1.0 + t, -t)
|
|
537
|
+
v_bary = bs[v_order]
|
|
538
|
+
|
|
539
|
+
dEdD, d2E_dDdD = evaluate_self_contact_force_norm(dis, collision_radius, collision_stiffness)
|
|
540
|
+
|
|
541
|
+
collision_force = -dEdD * v_bary * collision_normal
|
|
542
|
+
collision_hessian = d2E_dDdD * v_bary * v_bary * wp.outer(collision_normal, collision_normal)
|
|
543
|
+
|
|
544
|
+
# friction
|
|
545
|
+
c1_prev = pos_prev[e1_v1] + (pos_prev[e1_v2] - pos_prev[e1_v1]) * s
|
|
546
|
+
c2_prev = pos_prev[e2_v1] + (pos_prev[e2_v2] - pos_prev[e2_v1]) * t
|
|
547
|
+
|
|
548
|
+
dx = (c1 - c1_prev) - (c2 - c2_prev)
|
|
549
|
+
e1_vec_normalized = wp.normalize(e1_vec)
|
|
550
|
+
axis_2 = wp.normalize(wp.cross(e1_vec_normalized, collision_normal))
|
|
551
|
+
|
|
552
|
+
T = mat32(
|
|
553
|
+
e1_vec_normalized[0],
|
|
554
|
+
axis_2[0],
|
|
555
|
+
e1_vec_normalized[1],
|
|
556
|
+
axis_2[1],
|
|
557
|
+
e1_vec_normalized[2],
|
|
558
|
+
axis_2[2],
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
u = wp.transpose(T) * dx
|
|
562
|
+
eps_U = friction_epsilon * dt
|
|
563
|
+
|
|
564
|
+
# fmt: off
|
|
565
|
+
if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
566
|
+
wp.printf(
|
|
567
|
+
" collision force:\n %f %f %f,\n collision hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
|
|
568
|
+
collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
|
|
569
|
+
)
|
|
570
|
+
# fmt: on
|
|
571
|
+
|
|
572
|
+
friction_force, friction_hessian = compute_friction(friction_coefficient, -dEdD, T, u, eps_U)
|
|
573
|
+
friction_force = friction_force * v_bary
|
|
574
|
+
friction_hessian = friction_hessian * v_bary * v_bary
|
|
575
|
+
|
|
576
|
+
# fmt: off
|
|
577
|
+
if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
578
|
+
wp.printf(
|
|
579
|
+
" friction force:\n %f %f %f,\n friction hessian:\n %f %f %f,\n %f %f %f,\n %f %f %f\n",
|
|
580
|
+
friction_force[0], friction_force[1], friction_force[2], friction_hessian[0, 0], friction_hessian[0, 1], friction_hessian[0, 2], friction_hessian[1, 0], friction_hessian[1, 1], friction_hessian[1, 2], friction_hessian[2, 0], friction_hessian[2, 1], friction_hessian[2, 2],
|
|
581
|
+
)
|
|
582
|
+
# fmt: on
|
|
583
|
+
|
|
584
|
+
collision_force = collision_force + friction_force
|
|
585
|
+
collision_hessian = collision_hessian + friction_hessian
|
|
586
|
+
else:
|
|
587
|
+
collision_force = wp.vec3(0.0, 0.0, 0.0)
|
|
588
|
+
collision_hessian = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
589
|
+
|
|
590
|
+
return collision_force, collision_hessian
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
@wp.func
|
|
594
|
+
def evaluate_vertex_triangle_collision_force_hessian(
|
|
595
|
+
v: int,
|
|
596
|
+
v_order: int,
|
|
597
|
+
tri: int,
|
|
598
|
+
pos: wp.array(dtype=wp.vec3),
|
|
599
|
+
pos_prev: wp.array(dtype=wp.vec3),
|
|
600
|
+
tri_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
601
|
+
collision_radius: float,
|
|
602
|
+
collision_stiffness: float,
|
|
603
|
+
friction_coefficient: float,
|
|
604
|
+
friction_epsilon: float,
|
|
605
|
+
dt: float,
|
|
606
|
+
):
|
|
607
|
+
a = pos[tri_indices[tri, 0]]
|
|
608
|
+
b = pos[tri_indices[tri, 1]]
|
|
609
|
+
c = pos[tri_indices[tri, 2]]
|
|
610
|
+
|
|
611
|
+
p = pos[v]
|
|
612
|
+
|
|
613
|
+
closest_p, bary, feature_type = triangle_closest_point(a, b, c, p)
|
|
614
|
+
|
|
615
|
+
diff = p - closest_p
|
|
616
|
+
dis = wp.length(diff)
|
|
617
|
+
collision_normal = diff / dis
|
|
618
|
+
|
|
619
|
+
if dis < collision_radius:
|
|
620
|
+
bs = wp.vec4(-bary[0], -bary[1], -bary[2], 1.0)
|
|
621
|
+
v_bary = bs[v_order]
|
|
622
|
+
|
|
623
|
+
dEdD, d2E_dDdD = evaluate_self_contact_force_norm(dis, collision_radius, collision_stiffness)
|
|
624
|
+
|
|
625
|
+
collision_force = -dEdD * v_bary * collision_normal
|
|
626
|
+
collision_hessian = d2E_dDdD * v_bary * v_bary * wp.outer(collision_normal, collision_normal)
|
|
627
|
+
|
|
628
|
+
# friction force
|
|
629
|
+
dx_v = p - pos_prev[v]
|
|
630
|
+
|
|
631
|
+
closest_p_prev = (
|
|
632
|
+
bary[0] * pos_prev[tri_indices[tri, 0]]
|
|
633
|
+
+ bary[1] * pos_prev[tri_indices[tri, 1]]
|
|
634
|
+
+ bary[2] * pos_prev[tri_indices[tri, 2]]
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
dx = dx_v - (closest_p - closest_p_prev)
|
|
638
|
+
|
|
639
|
+
e0 = wp.normalize(b - a)
|
|
640
|
+
e1 = wp.normalize(wp.cross(e0, collision_normal))
|
|
641
|
+
|
|
642
|
+
T = mat32(e0[0], e1[0], e0[1], e1[1], e0[2], e1[2])
|
|
643
|
+
|
|
644
|
+
u = wp.transpose(T) * dx
|
|
645
|
+
eps_U = friction_epsilon * dt
|
|
646
|
+
|
|
647
|
+
friction_force, friction_hessian = compute_friction(friction_coefficient, -dEdD, T, u, eps_U)
|
|
648
|
+
|
|
649
|
+
# fmt: off
|
|
650
|
+
if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
651
|
+
wp.printf(
|
|
652
|
+
"v: %d dEdD: %f\nnormal force: %f %f %f\nfriction force: %f %f %f\n",
|
|
653
|
+
v,
|
|
654
|
+
dEdD,
|
|
655
|
+
collision_force[0], collision_force[1], collision_force[2], friction_force[0], friction_force[1], friction_force[2],
|
|
656
|
+
)
|
|
657
|
+
# fmt: on
|
|
658
|
+
|
|
659
|
+
collision_force = collision_force + v_bary * friction_force
|
|
660
|
+
collision_hessian = collision_hessian + v_bary * v_bary * friction_hessian
|
|
661
|
+
else:
|
|
662
|
+
collision_force = wp.vec3(0.0, 0.0, 0.0)
|
|
663
|
+
collision_hessian = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
664
|
+
|
|
665
|
+
return collision_force, collision_hessian
|
|
666
|
+
|
|
667
|
+
|
|
441
668
|
@wp.func
|
|
442
669
|
def compute_friction(mu: float, normal_contact_force: float, T: mat32, u: wp.vec2, eps_u: float):
|
|
443
670
|
"""
|
|
444
|
-
Returns the friction force and hessian.
|
|
671
|
+
Returns the 1D friction force and hessian.
|
|
445
672
|
Args:
|
|
446
673
|
mu: Friction coefficient.
|
|
447
674
|
normal_contact_force: normal contact force.
|
|
@@ -496,7 +723,126 @@ def forward_step(
|
|
|
496
723
|
|
|
497
724
|
|
|
498
725
|
@wp.kernel
|
|
499
|
-
def
|
|
726
|
+
def forward_step_penetration_free(
|
|
727
|
+
dt: float,
|
|
728
|
+
gravity: wp.vec3,
|
|
729
|
+
prev_pos: wp.array(dtype=wp.vec3),
|
|
730
|
+
pos: wp.array(dtype=wp.vec3),
|
|
731
|
+
vel: wp.array(dtype=wp.vec3),
|
|
732
|
+
inv_mass: wp.array(dtype=float),
|
|
733
|
+
external_force: wp.array(dtype=wp.vec3),
|
|
734
|
+
particle_flags: wp.array(dtype=wp.uint32),
|
|
735
|
+
pos_prev_collision_detection: wp.array(dtype=wp.vec3),
|
|
736
|
+
particle_conservative_bounds: wp.array(dtype=float),
|
|
737
|
+
inertia: wp.array(dtype=wp.vec3),
|
|
738
|
+
):
|
|
739
|
+
particle_index = wp.tid()
|
|
740
|
+
|
|
741
|
+
prev_pos[particle_index] = pos[particle_index]
|
|
742
|
+
if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
|
|
743
|
+
inertia[particle_index] = prev_pos[particle_index]
|
|
744
|
+
return
|
|
745
|
+
vel_new = vel[particle_index] + (gravity + external_force[particle_index] * inv_mass[particle_index]) * dt
|
|
746
|
+
pos_inertia = pos[particle_index] + vel_new * dt
|
|
747
|
+
inertia[particle_index] = pos_inertia
|
|
748
|
+
|
|
749
|
+
pos[particle_index] = apply_conservative_bound_truncation(
|
|
750
|
+
particle_index, pos_inertia, pos_prev_collision_detection, particle_conservative_bounds
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
@wp.kernel
|
|
755
|
+
def compute_particle_conservative_bound(
|
|
756
|
+
# inputs
|
|
757
|
+
conservative_bound_relaxation: float,
|
|
758
|
+
collision_query_radius: float,
|
|
759
|
+
adjacency: ForceElementAdjacencyInfo,
|
|
760
|
+
collision_info: TriMeshCollisionInfo,
|
|
761
|
+
# outputs
|
|
762
|
+
particle_conservative_bounds: wp.array(dtype=float),
|
|
763
|
+
):
|
|
764
|
+
particle_index = wp.tid()
|
|
765
|
+
min_dist = wp.min(collision_query_radius, collision_info.vertex_colliding_triangles_min_dist[particle_index])
|
|
766
|
+
|
|
767
|
+
# bound from neighbor triangles
|
|
768
|
+
for i_adj_tri in range(
|
|
769
|
+
get_vertex_num_adjacent_faces(
|
|
770
|
+
adjacency,
|
|
771
|
+
particle_index,
|
|
772
|
+
)
|
|
773
|
+
):
|
|
774
|
+
tri_index, vertex_order = get_vertex_adjacent_face_id_order(
|
|
775
|
+
adjacency,
|
|
776
|
+
particle_index,
|
|
777
|
+
i_adj_tri,
|
|
778
|
+
)
|
|
779
|
+
min_dist = wp.min(min_dist, collision_info.triangle_colliding_vertices_min_dist[tri_index])
|
|
780
|
+
|
|
781
|
+
# bound from neighbor edges
|
|
782
|
+
for i_adj_edge in range(
|
|
783
|
+
get_vertex_num_adjacent_edges(
|
|
784
|
+
adjacency,
|
|
785
|
+
particle_index,
|
|
786
|
+
)
|
|
787
|
+
):
|
|
788
|
+
nei_edge_index, vertex_order_on_edge = get_vertex_adjacent_edge_id_order(
|
|
789
|
+
adjacency,
|
|
790
|
+
particle_index,
|
|
791
|
+
i_adj_edge,
|
|
792
|
+
)
|
|
793
|
+
# vertex is on the edge; otherwise it only effects the bending energy
|
|
794
|
+
if vertex_order_on_edge == 2 or vertex_order_on_edge == 3:
|
|
795
|
+
# collisions of neighbor edges
|
|
796
|
+
min_dist = wp.min(min_dist, collision_info.edge_colliding_edges_min_dist[nei_edge_index])
|
|
797
|
+
|
|
798
|
+
particle_conservative_bounds[particle_index] = conservative_bound_relaxation * min_dist
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
@wp.kernel
|
|
802
|
+
def validate_conservative_bound(
|
|
803
|
+
pos: wp.array(dtype=wp.vec3),
|
|
804
|
+
pos_prev_collision_detection: wp.array(dtype=wp.vec3),
|
|
805
|
+
particle_conservative_bounds: wp.array(dtype=float),
|
|
806
|
+
):
|
|
807
|
+
v_index = wp.tid()
|
|
808
|
+
|
|
809
|
+
displacement = wp.length(pos[v_index] - pos_prev_collision_detection[v_index])
|
|
810
|
+
|
|
811
|
+
if displacement > particle_conservative_bounds[v_index] * 1.01 and displacement > 1e-5:
|
|
812
|
+
# wp.expect_eq(displacement <= particle_conservative_bounds[v_index] * 1.01, True)
|
|
813
|
+
wp.printf(
|
|
814
|
+
"Vertex %d has moved by %f exceeded the limit of %f\n",
|
|
815
|
+
v_index,
|
|
816
|
+
displacement,
|
|
817
|
+
particle_conservative_bounds[v_index],
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
@wp.func
|
|
822
|
+
def apply_conservative_bound_truncation(
|
|
823
|
+
v_index: wp.int32,
|
|
824
|
+
pos_new: wp.vec3,
|
|
825
|
+
pos_prev_collision_detection: wp.array(dtype=wp.vec3),
|
|
826
|
+
particle_conservative_bounds: wp.array(dtype=float),
|
|
827
|
+
):
|
|
828
|
+
particle_pos_prev_collision_detection = pos_prev_collision_detection[v_index]
|
|
829
|
+
accumulated_displacement = pos_new - particle_pos_prev_collision_detection
|
|
830
|
+
conservative_bound = particle_conservative_bounds[v_index]
|
|
831
|
+
|
|
832
|
+
accumulated_displacement_norm = wp.length(accumulated_displacement)
|
|
833
|
+
if accumulated_displacement_norm > conservative_bound and conservative_bound > 1e-5:
|
|
834
|
+
accumulated_displacement_norm_truncated = conservative_bound
|
|
835
|
+
accumulated_displacement = accumulated_displacement * (
|
|
836
|
+
accumulated_displacement_norm_truncated / accumulated_displacement_norm
|
|
837
|
+
)
|
|
838
|
+
|
|
839
|
+
return particle_pos_prev_collision_detection + accumulated_displacement
|
|
840
|
+
else:
|
|
841
|
+
return pos_new
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
@wp.kernel
|
|
845
|
+
def VBD_solve_trimesh_no_self_contact(
|
|
500
846
|
dt: float,
|
|
501
847
|
particle_ids_in_color: wp.array(dtype=wp.int32),
|
|
502
848
|
prev_pos: wp.array(dtype=wp.vec3),
|
|
@@ -538,7 +884,6 @@ def VBD_solve_trimesh(
|
|
|
538
884
|
tid = wp.tid()
|
|
539
885
|
|
|
540
886
|
particle_index = particle_ids_in_color[tid]
|
|
541
|
-
# wp.printf("vId: %d\n", particle)
|
|
542
887
|
|
|
543
888
|
if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
|
|
544
889
|
return
|
|
@@ -553,12 +898,24 @@ def VBD_solve_trimesh(
|
|
|
553
898
|
h = mass[particle_index] * dt_sqr_reciprocal * wp.identity(n=3, dtype=float)
|
|
554
899
|
|
|
555
900
|
# elastic force and hessian
|
|
556
|
-
for i_adj_tri in range(get_vertex_num_adjacent_faces(
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
901
|
+
for i_adj_tri in range(get_vertex_num_adjacent_faces(adjacency, particle_index)):
|
|
902
|
+
tri_id, particle_order = get_vertex_adjacent_face_id_order(adjacency, particle_index, i_adj_tri)
|
|
903
|
+
|
|
904
|
+
# fmt: off
|
|
905
|
+
if wp.static("connectivity" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
906
|
+
wp.printf(
|
|
907
|
+
"particle: %d | num_adj_faces: %d | ",
|
|
908
|
+
particle_index,
|
|
909
|
+
get_vertex_num_adjacent_faces(particle_index, adjacency),
|
|
910
|
+
)
|
|
911
|
+
wp.printf("i_face: %d | face id: %d | v_order: %d | ", i_adj_tri, tri_id, particle_order)
|
|
912
|
+
wp.printf(
|
|
913
|
+
"face: %d %d %d\n",
|
|
914
|
+
tri_indices[tri_id, 0],
|
|
915
|
+
tri_indices[tri_id, 1],
|
|
916
|
+
tri_indices[tri_id, 2],
|
|
917
|
+
)
|
|
918
|
+
# fmt: on
|
|
562
919
|
|
|
563
920
|
f_tri, h_tri = evaluate_stvk_force_hessian(
|
|
564
921
|
tri_id,
|
|
@@ -580,13 +937,16 @@ def VBD_solve_trimesh(
|
|
|
580
937
|
f = f + f_tri + f_d
|
|
581
938
|
h = h + h_tri + h_d
|
|
582
939
|
|
|
583
|
-
#
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
940
|
+
# fmt: off
|
|
941
|
+
if wp.static("elasticity_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
942
|
+
wp.printf(
|
|
943
|
+
"particle: %d, i_adj_tri: %d, particle_order: %d, \nforce:\n %f %f %f, \nhessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
|
|
944
|
+
particle_index,
|
|
945
|
+
i_adj_tri,
|
|
946
|
+
particle_order,
|
|
947
|
+
f[0], f[1], f[2], h[0, 0], h[0, 1], h[0, 2], h[1, 0], h[1, 1], h[1, 2], h[2, 0], h[2, 1], h[2, 2],
|
|
948
|
+
)
|
|
949
|
+
# fmt: on
|
|
590
950
|
|
|
591
951
|
# body-particle contact
|
|
592
952
|
particle_contact_count = min(body_particle_contact_count[particle_index], body_particle_contact_buffer_pre_alloc)
|
|
@@ -687,6 +1047,297 @@ def convert_body_particle_contact_data_kernel(
|
|
|
687
1047
|
body_particle_contact_buffer[offset + contact_counter] = contact_index
|
|
688
1048
|
|
|
689
1049
|
|
|
1050
|
+
@wp.kernel
|
|
1051
|
+
def VBD_solve_trimesh_with_self_contact_penetration_free(
|
|
1052
|
+
dt: float,
|
|
1053
|
+
particle_ids_in_color: wp.array(dtype=wp.int32),
|
|
1054
|
+
pos_prev: wp.array(dtype=wp.vec3),
|
|
1055
|
+
pos: wp.array(dtype=wp.vec3),
|
|
1056
|
+
pos_new: wp.array(dtype=wp.vec3),
|
|
1057
|
+
vel: wp.array(dtype=wp.vec3),
|
|
1058
|
+
mass: wp.array(dtype=float),
|
|
1059
|
+
inertia: wp.array(dtype=wp.vec3),
|
|
1060
|
+
particle_flags: wp.array(dtype=wp.uint32),
|
|
1061
|
+
tri_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
1062
|
+
tri_poses: wp.array(dtype=wp.mat22),
|
|
1063
|
+
tri_materials: wp.array(dtype=float, ndim=2),
|
|
1064
|
+
tri_areas: wp.array(dtype=float),
|
|
1065
|
+
edge_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
1066
|
+
adjacency: ForceElementAdjacencyInfo,
|
|
1067
|
+
# contact info
|
|
1068
|
+
# self contact
|
|
1069
|
+
collision_info: TriMeshCollisionInfo,
|
|
1070
|
+
collision_radius: float,
|
|
1071
|
+
soft_contact_ke: float,
|
|
1072
|
+
friction_mu: float,
|
|
1073
|
+
friction_epsilon: float,
|
|
1074
|
+
pos_prev_collision_detection: wp.array(dtype=wp.vec3),
|
|
1075
|
+
particle_conservative_bounds: wp.array(dtype=float),
|
|
1076
|
+
edge_edge_parallel_epsilon: float,
|
|
1077
|
+
# body-particle contact
|
|
1078
|
+
particle_radius: wp.array(dtype=float),
|
|
1079
|
+
body_particle_contact_buffer_pre_alloc: int,
|
|
1080
|
+
body_particle_contact_buffer: wp.array(dtype=int),
|
|
1081
|
+
body_particle_contact_count: wp.array(dtype=int),
|
|
1082
|
+
shape_materials: ModelShapeMaterials,
|
|
1083
|
+
shape_body: wp.array(dtype=int),
|
|
1084
|
+
body_q: wp.array(dtype=wp.transform),
|
|
1085
|
+
body_qd: wp.array(dtype=wp.spatial_vector),
|
|
1086
|
+
body_com: wp.array(dtype=wp.vec3),
|
|
1087
|
+
contact_shape: wp.array(dtype=int),
|
|
1088
|
+
contact_body_pos: wp.array(dtype=wp.vec3),
|
|
1089
|
+
contact_body_vel: wp.array(dtype=wp.vec3),
|
|
1090
|
+
contact_normal: wp.array(dtype=wp.vec3),
|
|
1091
|
+
# ground-particle contact
|
|
1092
|
+
has_ground: bool,
|
|
1093
|
+
ground: wp.array(dtype=float),
|
|
1094
|
+
):
|
|
1095
|
+
t_id = wp.tid()
|
|
1096
|
+
|
|
1097
|
+
particle_index = particle_ids_in_color[t_id]
|
|
1098
|
+
particle_pos = pos[particle_index]
|
|
1099
|
+
particle_prev_pos = pos_prev[particle_index]
|
|
1100
|
+
|
|
1101
|
+
if not particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE:
|
|
1102
|
+
return
|
|
1103
|
+
|
|
1104
|
+
dt_sqr_reciprocal = 1.0 / (dt * dt)
|
|
1105
|
+
|
|
1106
|
+
# inertia force and hessian
|
|
1107
|
+
f = mass[particle_index] * (inertia[particle_index] - pos[particle_index]) * (dt_sqr_reciprocal)
|
|
1108
|
+
h = mass[particle_index] * dt_sqr_reciprocal * wp.identity(n=3, dtype=float)
|
|
1109
|
+
|
|
1110
|
+
# fmt: off
|
|
1111
|
+
if wp.static("inertia_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1112
|
+
wp.printf(
|
|
1113
|
+
"particle: %d after accumulate inertia\nforce:\n %f %f %f, \nhessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
|
|
1114
|
+
particle_index,
|
|
1115
|
+
f[0], f[1], f[2], h[0, 0], h[0, 1], h[0, 2], h[1, 0], h[1, 1], h[1, 2], h[2, 0], h[2, 1], h[2, 2],
|
|
1116
|
+
)
|
|
1117
|
+
|
|
1118
|
+
# v-side of the v-f collision force
|
|
1119
|
+
if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1120
|
+
wp.printf("Has %d colliding triangles\n", get_vertex_colliding_triangles_count(collision_info, particle_index))
|
|
1121
|
+
for i_v_collision in range(get_vertex_colliding_triangles_count(collision_info, particle_index)):
|
|
1122
|
+
colliding_t = get_vertex_colliding_triangles(collision_info, particle_index, i_v_collision)
|
|
1123
|
+
if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1124
|
+
wp.printf(
|
|
1125
|
+
"vertex %d is colliding with triangle: %d-(%d, %d, %d)",
|
|
1126
|
+
particle_index,
|
|
1127
|
+
colliding_t,
|
|
1128
|
+
tri_indices[colliding_t, 0],
|
|
1129
|
+
tri_indices[colliding_t, 1],
|
|
1130
|
+
tri_indices[colliding_t, 2],
|
|
1131
|
+
)
|
|
1132
|
+
# fmt: on
|
|
1133
|
+
|
|
1134
|
+
collision_force, collision_hessian = evaluate_vertex_triangle_collision_force_hessian(
|
|
1135
|
+
particle_index,
|
|
1136
|
+
3,
|
|
1137
|
+
colliding_t,
|
|
1138
|
+
pos,
|
|
1139
|
+
pos_prev,
|
|
1140
|
+
tri_indices,
|
|
1141
|
+
collision_radius,
|
|
1142
|
+
soft_contact_ke,
|
|
1143
|
+
friction_mu,
|
|
1144
|
+
friction_epsilon,
|
|
1145
|
+
dt,
|
|
1146
|
+
)
|
|
1147
|
+
f = f + collision_force
|
|
1148
|
+
h = h + collision_hessian
|
|
1149
|
+
|
|
1150
|
+
# fmt: off
|
|
1151
|
+
if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1152
|
+
wp.printf(
|
|
1153
|
+
"vertex: %d collision %d:\nforce:\n %f %f %f, \nhessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
|
|
1154
|
+
particle_index,
|
|
1155
|
+
i_v_collision,
|
|
1156
|
+
collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
|
|
1157
|
+
)
|
|
1158
|
+
# fmt: on
|
|
1159
|
+
|
|
1160
|
+
# elastic force and hessian
|
|
1161
|
+
for i_adj_tri in range(get_vertex_num_adjacent_faces(adjacency, particle_index)):
|
|
1162
|
+
tri_index, vertex_order = get_vertex_adjacent_face_id_order(adjacency, particle_index, i_adj_tri)
|
|
1163
|
+
|
|
1164
|
+
# fmt: off
|
|
1165
|
+
if wp.static("connectivity" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1166
|
+
wp.printf(
|
|
1167
|
+
"particle: %d | num_adj_faces: %d | ",
|
|
1168
|
+
particle_index,
|
|
1169
|
+
get_vertex_num_adjacent_faces(particle_index, adjacency),
|
|
1170
|
+
)
|
|
1171
|
+
wp.printf("i_face: %d | face id: %d | v_order: %d | ", i_adj_tri, tri_index, vertex_order)
|
|
1172
|
+
wp.printf(
|
|
1173
|
+
"face: %d %d %d\n",
|
|
1174
|
+
tri_indices[tri_index, 0],
|
|
1175
|
+
tri_indices[tri_index, 1],
|
|
1176
|
+
tri_indices[tri_index, 2],
|
|
1177
|
+
)
|
|
1178
|
+
# fmt: on
|
|
1179
|
+
|
|
1180
|
+
f_tri, h_tri = evaluate_stvk_force_hessian(
|
|
1181
|
+
tri_index,
|
|
1182
|
+
vertex_order,
|
|
1183
|
+
pos,
|
|
1184
|
+
tri_indices,
|
|
1185
|
+
tri_poses[tri_index],
|
|
1186
|
+
tri_areas[tri_index],
|
|
1187
|
+
tri_materials[tri_index, 0],
|
|
1188
|
+
tri_materials[tri_index, 1],
|
|
1189
|
+
tri_materials[tri_index, 2],
|
|
1190
|
+
)
|
|
1191
|
+
# compute damping
|
|
1192
|
+
k_d = tri_materials[tri_index, 2]
|
|
1193
|
+
h_d = h_tri * (k_d / dt)
|
|
1194
|
+
|
|
1195
|
+
f_d = h_d * (pos_prev[particle_index] - pos[particle_index])
|
|
1196
|
+
|
|
1197
|
+
f = f + f_tri + f_d
|
|
1198
|
+
h = h + h_tri + h_d
|
|
1199
|
+
|
|
1200
|
+
# t-side of vt-collision from the neighbor triangles
|
|
1201
|
+
# fmt: off
|
|
1202
|
+
if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1203
|
+
wp.printf(
|
|
1204
|
+
"Nei triangle %d has %d colliding vertice\n",
|
|
1205
|
+
tri_index,
|
|
1206
|
+
get_triangle_colliding_vertices_count(collision_info, tri_index),
|
|
1207
|
+
)
|
|
1208
|
+
# fmt: on
|
|
1209
|
+
for i_t_collision in range(get_triangle_colliding_vertices_count(collision_info, tri_index)):
|
|
1210
|
+
colliding_v = get_triangle_colliding_vertices(collision_info, tri_index, i_t_collision)
|
|
1211
|
+
|
|
1212
|
+
collision_force, collision_hessian = evaluate_vertex_triangle_collision_force_hessian(
|
|
1213
|
+
colliding_v,
|
|
1214
|
+
vertex_order,
|
|
1215
|
+
tri_index,
|
|
1216
|
+
pos,
|
|
1217
|
+
pos_prev,
|
|
1218
|
+
tri_indices,
|
|
1219
|
+
collision_radius,
|
|
1220
|
+
soft_contact_ke,
|
|
1221
|
+
friction_mu,
|
|
1222
|
+
friction_epsilon,
|
|
1223
|
+
dt,
|
|
1224
|
+
)
|
|
1225
|
+
|
|
1226
|
+
f = f + collision_force
|
|
1227
|
+
h = h + collision_hessian
|
|
1228
|
+
|
|
1229
|
+
# edge-edge collision force and hessian
|
|
1230
|
+
for i_adj_edge in range(get_vertex_num_adjacent_edges(adjacency, particle_index)):
|
|
1231
|
+
nei_edge_index, vertex_order_on_edge = get_vertex_adjacent_edge_id_order(adjacency, particle_index, i_adj_edge)
|
|
1232
|
+
# vertex is on the edge; otherwise it only effects the bending energy n
|
|
1233
|
+
if vertex_order_on_edge == 2 or vertex_order_on_edge == 3:
|
|
1234
|
+
# collisions of neighbor triangles
|
|
1235
|
+
if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1236
|
+
wp.printf(
|
|
1237
|
+
"Nei edge %d has %d colliding edge\n",
|
|
1238
|
+
nei_edge_index,
|
|
1239
|
+
get_edge_colliding_edges_count(collision_info, nei_edge_index),
|
|
1240
|
+
)
|
|
1241
|
+
for i_e_collision in range(get_edge_colliding_edges_count(collision_info, nei_edge_index)):
|
|
1242
|
+
colliding_e = get_edge_colliding_edges(collision_info, nei_edge_index, i_e_collision)
|
|
1243
|
+
|
|
1244
|
+
collision_force, collision_hessian = evaluate_edge_edge_contact(
|
|
1245
|
+
particle_index,
|
|
1246
|
+
vertex_order_on_edge - 2,
|
|
1247
|
+
nei_edge_index,
|
|
1248
|
+
colliding_e,
|
|
1249
|
+
pos,
|
|
1250
|
+
pos_prev,
|
|
1251
|
+
edge_indices,
|
|
1252
|
+
collision_radius,
|
|
1253
|
+
soft_contact_ke,
|
|
1254
|
+
friction_mu,
|
|
1255
|
+
friction_epsilon,
|
|
1256
|
+
dt,
|
|
1257
|
+
edge_edge_parallel_epsilon,
|
|
1258
|
+
)
|
|
1259
|
+
f = f + collision_force
|
|
1260
|
+
h = h + collision_hessian
|
|
1261
|
+
|
|
1262
|
+
# fmt: off
|
|
1263
|
+
if wp.static("contact_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1264
|
+
wp.printf(
|
|
1265
|
+
"vertex: %d edge %d collision %d:\nforce:\n %f %f %f, \nhessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
|
|
1266
|
+
particle_index,
|
|
1267
|
+
nei_edge_index,
|
|
1268
|
+
i_e_collision,
|
|
1269
|
+
collision_force[0], collision_force[1], collision_force[2], collision_hessian[0, 0], collision_hessian[0, 1], collision_hessian[0, 2], collision_hessian[1, 0], collision_hessian[1, 1], collision_hessian[1, 2], collision_hessian[2, 0], collision_hessian[2, 1], collision_hessian[2, 2],
|
|
1270
|
+
)
|
|
1271
|
+
# fmt: on
|
|
1272
|
+
|
|
1273
|
+
# body-particle contact
|
|
1274
|
+
particle_contact_count = min(body_particle_contact_count[particle_index], body_particle_contact_buffer_pre_alloc)
|
|
1275
|
+
|
|
1276
|
+
offset = body_particle_contact_buffer_pre_alloc * particle_index
|
|
1277
|
+
for contact_counter in range(particle_contact_count):
|
|
1278
|
+
# the index to access body-particle data, which is size-variable and only contains active contact
|
|
1279
|
+
contact_index = body_particle_contact_buffer[offset + contact_counter]
|
|
1280
|
+
|
|
1281
|
+
body_contact_force, body_contact_hessian = evaluate_body_particle_contact(
|
|
1282
|
+
particle_index,
|
|
1283
|
+
particle_pos,
|
|
1284
|
+
particle_prev_pos,
|
|
1285
|
+
contact_index,
|
|
1286
|
+
soft_contact_ke,
|
|
1287
|
+
friction_mu,
|
|
1288
|
+
friction_epsilon,
|
|
1289
|
+
particle_radius,
|
|
1290
|
+
shape_materials,
|
|
1291
|
+
shape_body,
|
|
1292
|
+
body_q,
|
|
1293
|
+
body_qd,
|
|
1294
|
+
body_com,
|
|
1295
|
+
contact_shape,
|
|
1296
|
+
contact_body_pos,
|
|
1297
|
+
contact_body_vel,
|
|
1298
|
+
contact_normal,
|
|
1299
|
+
dt,
|
|
1300
|
+
)
|
|
1301
|
+
|
|
1302
|
+
f = f + body_contact_force
|
|
1303
|
+
h = h + body_contact_hessian
|
|
1304
|
+
|
|
1305
|
+
if has_ground:
|
|
1306
|
+
ground_normal = wp.vec3(ground[0], ground[1], ground[2])
|
|
1307
|
+
ground_level = ground[3]
|
|
1308
|
+
ground_contact_force, ground_contact_hessian = evaluate_ground_contact_force_hessian(
|
|
1309
|
+
particle_pos,
|
|
1310
|
+
particle_prev_pos,
|
|
1311
|
+
particle_radius[particle_index],
|
|
1312
|
+
ground_normal,
|
|
1313
|
+
ground_level,
|
|
1314
|
+
soft_contact_ke,
|
|
1315
|
+
friction_mu,
|
|
1316
|
+
friction_epsilon,
|
|
1317
|
+
dt,
|
|
1318
|
+
)
|
|
1319
|
+
|
|
1320
|
+
f = f + ground_contact_force
|
|
1321
|
+
h = h + ground_contact_hessian
|
|
1322
|
+
|
|
1323
|
+
# fmt: off
|
|
1324
|
+
if wp.static("overall_force_hessian" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
1325
|
+
wp.printf(
|
|
1326
|
+
"vertex: %d final\noverall force:\n %f %f %f, \noverall hessian:, \n%f %f %f, \n%f %f %f, \n%f %f %f\n",
|
|
1327
|
+
particle_index,
|
|
1328
|
+
f[0], f[1], f[2], h[0, 0], h[0, 1], h[0, 2], h[1, 0], h[1, 1], h[1, 2], h[2, 0], h[2, 1], h[2, 2],
|
|
1329
|
+
)
|
|
1330
|
+
# fmt: on
|
|
1331
|
+
|
|
1332
|
+
if abs(wp.determinant(h)) > 1e-5:
|
|
1333
|
+
h_inv = wp.inverse(h)
|
|
1334
|
+
particle_pos_new = pos[particle_index] + h_inv * f
|
|
1335
|
+
|
|
1336
|
+
pos_new[particle_index] = apply_conservative_bound_truncation(
|
|
1337
|
+
particle_index, particle_pos_new, pos_prev_collision_detection, particle_conservative_bounds
|
|
1338
|
+
)
|
|
1339
|
+
|
|
1340
|
+
|
|
690
1341
|
class VBDIntegrator(Integrator):
|
|
691
1342
|
"""An implicit integrator using Vertex Block Descent (VBD) for cloth simulation.
|
|
692
1343
|
|
|
@@ -718,8 +1369,14 @@ class VBDIntegrator(Integrator):
|
|
|
718
1369
|
self,
|
|
719
1370
|
model: Model,
|
|
720
1371
|
iterations=10,
|
|
721
|
-
|
|
1372
|
+
handle_self_contact=False,
|
|
1373
|
+
penetration_free_conservative_bound_relaxation=0.42,
|
|
722
1374
|
friction_epsilon=1e-2,
|
|
1375
|
+
body_particle_contact_buffer_pre_alloc=4,
|
|
1376
|
+
vertex_collision_buffer_pre_alloc=32,
|
|
1377
|
+
edge_collision_buffer_pre_alloc=64,
|
|
1378
|
+
triangle_collision_buffer_pre_alloc=32,
|
|
1379
|
+
edge_edge_parallel_epsilon=1e-5,
|
|
723
1380
|
):
|
|
724
1381
|
self.device = model.device
|
|
725
1382
|
self.model = model
|
|
@@ -731,6 +1388,7 @@ class VBDIntegrator(Integrator):
|
|
|
731
1388
|
|
|
732
1389
|
self.adjacency = self.compute_force_element_adjacency(model).to(self.device)
|
|
733
1390
|
|
|
1391
|
+
# data for body-particle collision
|
|
734
1392
|
self.body_particle_contact_buffer_pre_alloc = body_particle_contact_buffer_pre_alloc
|
|
735
1393
|
self.body_particle_contact_buffer = wp.zeros(
|
|
736
1394
|
(self.body_particle_contact_buffer_pre_alloc * model.particle_count,),
|
|
@@ -738,6 +1396,28 @@ class VBDIntegrator(Integrator):
|
|
|
738
1396
|
device=self.device,
|
|
739
1397
|
)
|
|
740
1398
|
self.body_particle_contact_count = wp.zeros((model.particle_count,), dtype=wp.int32, device=self.device)
|
|
1399
|
+
|
|
1400
|
+
self.handle_self_contact = handle_self_contact
|
|
1401
|
+
|
|
1402
|
+
if handle_self_contact:
|
|
1403
|
+
if self.model.soft_contact_margin < self.model.soft_contact_radius:
|
|
1404
|
+
raise ValueError(
|
|
1405
|
+
"model.soft_contact_margin is smaller than self.model.soft_contact_radius, this will result in missing contacts and cause instability. \n"
|
|
1406
|
+
"It is advisable to make model.soft_contact_margin 1.5~2 times larger than self.model.soft_contact_radius."
|
|
1407
|
+
)
|
|
1408
|
+
|
|
1409
|
+
self.conservative_bound_relaxation = penetration_free_conservative_bound_relaxation
|
|
1410
|
+
self.pos_prev_collision_detection = wp.zeros_like(model.particle_q, device=self.device)
|
|
1411
|
+
self.particle_conservative_bounds = wp.full((model.particle_count,), dtype=float, device=self.device)
|
|
1412
|
+
|
|
1413
|
+
self.trimesh_collision_detector = TriMeshCollisionDetector(
|
|
1414
|
+
self.model,
|
|
1415
|
+
vertex_collision_buffer_pre_alloc=vertex_collision_buffer_pre_alloc,
|
|
1416
|
+
edge_collision_buffer_pre_alloc=edge_collision_buffer_pre_alloc,
|
|
1417
|
+
triangle_collision_buffer_pre_alloc=triangle_collision_buffer_pre_alloc,
|
|
1418
|
+
edge_edge_parallel_epsilon=edge_edge_parallel_epsilon,
|
|
1419
|
+
)
|
|
1420
|
+
|
|
741
1421
|
self.friction_epsilon = friction_epsilon
|
|
742
1422
|
|
|
743
1423
|
if len(self.model.particle_coloring) == 0:
|
|
@@ -837,6 +1517,14 @@ class VBDIntegrator(Integrator):
|
|
|
837
1517
|
if model is not self.model:
|
|
838
1518
|
raise ValueError("model must be the one used to initialize VBDIntegrator")
|
|
839
1519
|
|
|
1520
|
+
if self.handle_self_contact:
|
|
1521
|
+
self.simulate_one_step_with_collisions_penetration_free(model, state_in, state_out, dt, control)
|
|
1522
|
+
else:
|
|
1523
|
+
self.simulate_one_step_no_self_contact(model, state_in, state_out, dt, control)
|
|
1524
|
+
|
|
1525
|
+
def simulate_one_step_no_self_contact(
|
|
1526
|
+
self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None
|
|
1527
|
+
):
|
|
840
1528
|
self.convert_body_particle_contact_data()
|
|
841
1529
|
|
|
842
1530
|
wp.launch(
|
|
@@ -859,7 +1547,7 @@ class VBDIntegrator(Integrator):
|
|
|
859
1547
|
for _iter in range(self.iterations):
|
|
860
1548
|
for color_counter in range(len(self.model.particle_coloring)):
|
|
861
1549
|
wp.launch(
|
|
862
|
-
kernel=
|
|
1550
|
+
kernel=VBD_solve_trimesh_no_self_contact,
|
|
863
1551
|
inputs=[
|
|
864
1552
|
dt,
|
|
865
1553
|
self.model.particle_coloring[color_counter],
|
|
@@ -914,6 +1602,120 @@ class VBDIntegrator(Integrator):
|
|
|
914
1602
|
device=self.device,
|
|
915
1603
|
)
|
|
916
1604
|
|
|
1605
|
+
def simulate_one_step_with_collisions_penetration_free(
|
|
1606
|
+
self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None
|
|
1607
|
+
):
|
|
1608
|
+
self.convert_body_particle_contact_data()
|
|
1609
|
+
# collision detection before initialization to compute conservative bounds for initialization
|
|
1610
|
+
self.collision_detection_penetration_free(state_in, dt)
|
|
1611
|
+
|
|
1612
|
+
wp.launch(
|
|
1613
|
+
kernel=forward_step_penetration_free,
|
|
1614
|
+
inputs=[
|
|
1615
|
+
dt,
|
|
1616
|
+
model.gravity,
|
|
1617
|
+
self.particle_q_prev,
|
|
1618
|
+
state_in.particle_q,
|
|
1619
|
+
state_in.particle_qd,
|
|
1620
|
+
self.model.particle_inv_mass,
|
|
1621
|
+
state_in.particle_f,
|
|
1622
|
+
self.model.particle_flags,
|
|
1623
|
+
self.pos_prev_collision_detection,
|
|
1624
|
+
self.particle_conservative_bounds,
|
|
1625
|
+
self.inertia,
|
|
1626
|
+
],
|
|
1627
|
+
dim=self.model.particle_count,
|
|
1628
|
+
device=self.device,
|
|
1629
|
+
)
|
|
1630
|
+
|
|
1631
|
+
# after initialization, we do another collision detection to update the bounds
|
|
1632
|
+
self.collision_detection_penetration_free(state_in, dt)
|
|
1633
|
+
|
|
1634
|
+
for _iter in range(self.iterations):
|
|
1635
|
+
for i_color in range(len(self.model.particle_coloring)):
|
|
1636
|
+
wp.launch(
|
|
1637
|
+
kernel=VBD_solve_trimesh_with_self_contact_penetration_free,
|
|
1638
|
+
inputs=[
|
|
1639
|
+
dt,
|
|
1640
|
+
self.model.particle_coloring[i_color],
|
|
1641
|
+
self.particle_q_prev,
|
|
1642
|
+
state_in.particle_q,
|
|
1643
|
+
state_out.particle_q,
|
|
1644
|
+
state_in.particle_qd,
|
|
1645
|
+
self.model.particle_mass,
|
|
1646
|
+
self.inertia,
|
|
1647
|
+
self.model.particle_flags,
|
|
1648
|
+
self.model.tri_indices,
|
|
1649
|
+
self.model.tri_poses,
|
|
1650
|
+
self.model.tri_materials,
|
|
1651
|
+
self.model.tri_areas,
|
|
1652
|
+
self.model.edge_indices,
|
|
1653
|
+
self.adjacency,
|
|
1654
|
+
# self-contact
|
|
1655
|
+
self.trimesh_collision_detector.collision_info,
|
|
1656
|
+
self.model.soft_contact_radius,
|
|
1657
|
+
self.model.soft_contact_ke,
|
|
1658
|
+
self.model.soft_contact_mu,
|
|
1659
|
+
self.friction_epsilon,
|
|
1660
|
+
self.pos_prev_collision_detection,
|
|
1661
|
+
self.particle_conservative_bounds,
|
|
1662
|
+
self.trimesh_collision_detector.edge_edge_parallel_epsilon,
|
|
1663
|
+
# body-particle contact
|
|
1664
|
+
self.model.particle_radius,
|
|
1665
|
+
self.body_particle_contact_buffer_pre_alloc,
|
|
1666
|
+
self.body_particle_contact_buffer,
|
|
1667
|
+
self.body_particle_contact_count,
|
|
1668
|
+
self.model.shape_materials,
|
|
1669
|
+
self.model.shape_body,
|
|
1670
|
+
self.model.body_q,
|
|
1671
|
+
self.model.body_qd,
|
|
1672
|
+
self.model.body_com,
|
|
1673
|
+
self.model.soft_contact_shape,
|
|
1674
|
+
self.model.soft_contact_body_pos,
|
|
1675
|
+
self.model.soft_contact_body_vel,
|
|
1676
|
+
self.model.soft_contact_normal,
|
|
1677
|
+
self.model.ground,
|
|
1678
|
+
self.model.ground_plane,
|
|
1679
|
+
],
|
|
1680
|
+
dim=self.model.particle_coloring[i_color].shape[0],
|
|
1681
|
+
device=self.device,
|
|
1682
|
+
)
|
|
1683
|
+
|
|
1684
|
+
wp.launch(
|
|
1685
|
+
kernel=VBD_copy_particle_positions_back,
|
|
1686
|
+
inputs=[self.model.particle_coloring[i_color], state_in.particle_q, state_out.particle_q],
|
|
1687
|
+
dim=self.model.particle_coloring[i_color].size,
|
|
1688
|
+
device=self.device,
|
|
1689
|
+
)
|
|
1690
|
+
|
|
1691
|
+
wp.launch(
|
|
1692
|
+
kernel=update_velocity,
|
|
1693
|
+
inputs=[dt, self.particle_q_prev, state_out.particle_q, state_out.particle_qd],
|
|
1694
|
+
dim=self.model.particle_count,
|
|
1695
|
+
device=self.device,
|
|
1696
|
+
)
|
|
1697
|
+
|
|
1698
|
+
def collision_detection_penetration_free(self, current_state, dt):
|
|
1699
|
+
self.trimesh_collision_detector.refit(current_state.particle_q)
|
|
1700
|
+
self.trimesh_collision_detector.vertex_triangle_collision_detection(self.model.soft_contact_margin)
|
|
1701
|
+
self.trimesh_collision_detector.edge_edge_collision_detection(self.model.soft_contact_margin)
|
|
1702
|
+
|
|
1703
|
+
self.pos_prev_collision_detection.assign(current_state.particle_q)
|
|
1704
|
+
wp.launch(
|
|
1705
|
+
kernel=compute_particle_conservative_bound,
|
|
1706
|
+
inputs=[
|
|
1707
|
+
self.conservative_bound_relaxation,
|
|
1708
|
+
self.model.soft_contact_margin,
|
|
1709
|
+
self.adjacency,
|
|
1710
|
+
self.trimesh_collision_detector.collision_info,
|
|
1711
|
+
],
|
|
1712
|
+
outputs=[
|
|
1713
|
+
self.particle_conservative_bounds,
|
|
1714
|
+
],
|
|
1715
|
+
dim=self.model.particle_count,
|
|
1716
|
+
device=self.device,
|
|
1717
|
+
)
|
|
1718
|
+
|
|
917
1719
|
def convert_body_particle_contact_data(self):
|
|
918
1720
|
self.body_particle_contact_count.zero_()
|
|
919
1721
|
|