warp-lang 0.15.0__py3-none-manylinux2014_x86_64.whl → 1.0.0__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 +1 -0
- warp/codegen.py +7 -3
- warp/config.py +2 -1
- warp/constants.py +3 -0
- warp/context.py +44 -21
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/assets/cartpole.urdf +110 -0
- warp/examples/assets/crazyflie.usd +0 -0
- warp/examples/assets/cube.usda +42 -0
- warp/examples/assets/nv_ant.xml +92 -0
- warp/examples/assets/nv_humanoid.xml +183 -0
- warp/examples/assets/quadruped.urdf +268 -0
- warp/examples/assets/rocks.nvdb +0 -0
- warp/examples/assets/rocks.usd +0 -0
- warp/examples/assets/sphere.usda +56 -0
- warp/examples/assets/torus.usda +105 -0
- warp/examples/core/example_dem.py +6 -6
- warp/examples/core/example_fluid.py +3 -3
- warp/examples/core/example_graph_capture.py +3 -6
- warp/examples/optim/example_bounce.py +9 -8
- warp/examples/optim/example_cloth_throw.py +12 -8
- warp/examples/optim/example_diffray.py +10 -12
- warp/examples/optim/example_drone.py +31 -14
- warp/examples/optim/example_spring_cage.py +10 -15
- warp/examples/optim/example_trajectory.py +7 -24
- warp/examples/sim/example_cartpole.py +3 -9
- warp/examples/sim/example_cloth.py +10 -10
- warp/examples/sim/example_granular.py +3 -3
- warp/examples/sim/example_granular_collision_sdf.py +9 -4
- warp/examples/sim/example_jacobian_ik.py +0 -10
- warp/examples/sim/example_particle_chain.py +4 -4
- warp/examples/sim/example_quadruped.py +15 -11
- warp/examples/sim/example_rigid_chain.py +13 -8
- warp/examples/sim/example_rigid_contact.py +4 -4
- warp/examples/sim/example_rigid_force.py +7 -7
- warp/examples/sim/example_rigid_soft_contact.py +4 -4
- warp/examples/sim/example_soft_body.py +3 -3
- warp/jax.py +45 -0
- warp/jax_experimental.py +339 -0
- warp/render/render_opengl.py +188 -95
- warp/render/render_usd.py +34 -10
- warp/sim/__init__.py +13 -4
- warp/sim/articulation.py +4 -5
- warp/sim/collide.py +320 -175
- warp/sim/import_mjcf.py +25 -30
- warp/sim/import_urdf.py +94 -63
- warp/sim/import_usd.py +51 -36
- warp/sim/inertia.py +3 -2
- warp/sim/integrator.py +233 -0
- warp/sim/integrator_euler.py +447 -469
- warp/sim/integrator_featherstone.py +1991 -0
- warp/sim/integrator_xpbd.py +1420 -640
- warp/sim/model.py +741 -487
- warp/sim/particles.py +2 -1
- warp/sim/render.py +18 -2
- warp/sim/utils.py +222 -11
- warp/stubs.py +1 -0
- warp/tape.py +6 -9
- warp/tests/test_examples.py +87 -20
- warp/tests/test_grad_customs.py +122 -0
- warp/tests/test_jax.py +254 -0
- warp/tests/test_options.py +13 -53
- warp/tests/test_quat.py +23 -0
- warp/tests/test_snippet.py +2 -0
- warp/tests/test_utils.py +31 -26
- warp/tests/test_verify_fp.py +65 -0
- warp/tests/unittest_suites.py +4 -0
- warp/utils.py +50 -1
- {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/METADATA +1 -1
- {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +73 -64
- warp/examples/env/__init__.py +0 -0
- warp/examples/env/env_ant.py +0 -61
- warp/examples/env/env_cartpole.py +0 -63
- warp/examples/env/env_humanoid.py +0 -65
- warp/examples/env/env_usd.py +0 -97
- warp/examples/env/environment.py +0 -526
- warp/sim/optimizer.py +0 -138
- {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
- {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/top_level.txt +0 -0
warp/sim/integrator_xpbd.py
CHANGED
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
|
7
7
|
|
|
8
8
|
import warp as wp
|
|
9
|
+
from .integrator import Integrator
|
|
9
10
|
from .model import (
|
|
11
|
+
Model,
|
|
12
|
+
State,
|
|
13
|
+
Control,
|
|
10
14
|
PARTICLE_FLAG_ACTIVE,
|
|
11
15
|
ModelShapeMaterials,
|
|
12
16
|
JOINT_MODE_TARGET_POSITION,
|
|
13
17
|
JOINT_MODE_TARGET_VELOCITY,
|
|
14
|
-
|
|
18
|
+
JOINT_MODE_FORCE,
|
|
15
19
|
)
|
|
16
|
-
from .utils import velocity_at_point, vec_min, vec_max, vec_abs
|
|
17
|
-
from .integrator_euler import integrate_bodies, integrate_particles
|
|
20
|
+
from .utils import velocity_at_point, vec_min, vec_max, vec_abs, vec_leaky_min, vec_leaky_max
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
@wp.kernel
|
|
@@ -61,18 +64,106 @@ def solve_particle_ground_contacts(
|
|
|
61
64
|
lambda_f = wp.max(mu * lambda_n, 0.0 - wp.length(vt) * dt)
|
|
62
65
|
delta_f = wp.normalize(vt) * lambda_f
|
|
63
66
|
|
|
64
|
-
wp.atomic_add(delta, tid, (delta_f - delta_n)
|
|
67
|
+
wp.atomic_add(delta, tid, (delta_f - delta_n) * relaxation)
|
|
65
68
|
|
|
66
69
|
|
|
67
70
|
@wp.kernel
|
|
68
|
-
def
|
|
71
|
+
def apply_particle_shape_restitution(
|
|
69
72
|
particle_x_new: wp.array(dtype=wp.vec3),
|
|
70
73
|
particle_v_new: wp.array(dtype=wp.vec3),
|
|
71
74
|
particle_x_old: wp.array(dtype=wp.vec3),
|
|
72
75
|
particle_v_old: wp.array(dtype=wp.vec3),
|
|
73
|
-
|
|
76
|
+
particle_invmass: wp.array(dtype=float),
|
|
77
|
+
particle_radius: wp.array(dtype=float),
|
|
78
|
+
particle_flags: wp.array(dtype=wp.uint32),
|
|
79
|
+
body_q: wp.array(dtype=wp.transform),
|
|
80
|
+
body_qd: wp.array(dtype=wp.spatial_vector),
|
|
81
|
+
body_com: wp.array(dtype=wp.vec3),
|
|
82
|
+
body_m_inv: wp.array(dtype=float),
|
|
83
|
+
body_I_inv: wp.array(dtype=wp.mat33),
|
|
84
|
+
shape_body: wp.array(dtype=int),
|
|
85
|
+
shape_materials: ModelShapeMaterials,
|
|
86
|
+
particle_ka: float,
|
|
87
|
+
restitution: float,
|
|
88
|
+
contact_count: wp.array(dtype=int),
|
|
89
|
+
contact_particle: wp.array(dtype=int),
|
|
90
|
+
contact_shape: wp.array(dtype=int),
|
|
91
|
+
contact_body_pos: wp.array(dtype=wp.vec3),
|
|
92
|
+
contact_body_vel: wp.array(dtype=wp.vec3),
|
|
93
|
+
contact_normal: wp.array(dtype=wp.vec3),
|
|
94
|
+
contact_max: int,
|
|
95
|
+
dt: float,
|
|
96
|
+
relaxation: float,
|
|
97
|
+
particle_v_out: wp.array(dtype=wp.vec3),
|
|
98
|
+
):
|
|
99
|
+
tid = wp.tid()
|
|
100
|
+
|
|
101
|
+
count = min(contact_max, contact_count[0])
|
|
102
|
+
if tid >= count:
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
shape_index = contact_shape[tid]
|
|
106
|
+
body_index = shape_body[shape_index]
|
|
107
|
+
particle_index = contact_particle[tid]
|
|
108
|
+
|
|
109
|
+
if (particle_flags[particle_index] & PARTICLE_FLAG_ACTIVE) == 0:
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
# x_new = particle_x_new[particle_index]
|
|
113
|
+
v_new = particle_v_new[particle_index]
|
|
114
|
+
px = particle_x_old[particle_index]
|
|
115
|
+
v_old = particle_v_old[particle_index]
|
|
116
|
+
|
|
117
|
+
X_wb = wp.transform_identity()
|
|
118
|
+
X_com = wp.vec3()
|
|
119
|
+
|
|
120
|
+
if body_index >= 0:
|
|
121
|
+
X_wb = body_q[body_index]
|
|
122
|
+
X_com = body_com[body_index]
|
|
123
|
+
|
|
124
|
+
# body position in world space
|
|
125
|
+
bx = wp.transform_point(X_wb, contact_body_pos[tid])
|
|
126
|
+
r = bx - wp.transform_point(X_wb, X_com)
|
|
127
|
+
|
|
128
|
+
n = contact_normal[tid]
|
|
129
|
+
c = wp.dot(n, px - bx) - particle_radius[particle_index]
|
|
130
|
+
|
|
131
|
+
if c > particle_ka:
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
rel_vel_old = wp.dot(n, v_old)
|
|
135
|
+
rel_vel_new = wp.dot(n, v_new)
|
|
136
|
+
|
|
137
|
+
if rel_vel_old < 0.0:
|
|
138
|
+
# dv = -n * wp.max(-rel_vel_new + wp.max(-restitution * rel_vel_old, 0.0), 0.0)
|
|
139
|
+
dv = n * (-rel_vel_new + wp.max(-restitution * rel_vel_old, 0.0))
|
|
140
|
+
|
|
141
|
+
# compute inverse masses
|
|
142
|
+
# w1 = particle_invmass[particle_index]
|
|
143
|
+
# w2 = 0.0
|
|
144
|
+
# if body_index >= 0:
|
|
145
|
+
# angular = wp.cross(r, n)
|
|
146
|
+
# q = wp.transform_get_rotation(X_wb)
|
|
147
|
+
# rot_angular = wp.quat_rotate_inv(q, angular)
|
|
148
|
+
# I_inv = body_I_inv[body_index]
|
|
149
|
+
# w2 = body_m_inv[body_index] + wp.dot(rot_angular, I_inv * rot_angular)
|
|
150
|
+
# denom = w1 + w2
|
|
151
|
+
# if denom == 0.0:
|
|
152
|
+
# return
|
|
153
|
+
|
|
154
|
+
wp.atomic_add(particle_v_out, tid, dv)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@wp.kernel
|
|
158
|
+
def apply_particle_ground_restitution(
|
|
159
|
+
particle_x_new: wp.array(dtype=wp.vec3),
|
|
160
|
+
particle_v_new: wp.array(dtype=wp.vec3),
|
|
161
|
+
particle_x_old: wp.array(dtype=wp.vec3),
|
|
162
|
+
particle_v_old: wp.array(dtype=wp.vec3),
|
|
163
|
+
particle_invmass: wp.array(dtype=float),
|
|
74
164
|
particle_radius: wp.array(dtype=float),
|
|
75
165
|
particle_flags: wp.array(dtype=wp.uint32),
|
|
166
|
+
particle_ka: float,
|
|
76
167
|
restitution: float,
|
|
77
168
|
ground: wp.array(dtype=float),
|
|
78
169
|
dt: float,
|
|
@@ -83,26 +174,26 @@ def apply_soft_restitution_ground(
|
|
|
83
174
|
if (particle_flags[tid] & PARTICLE_FLAG_ACTIVE) == 0:
|
|
84
175
|
return
|
|
85
176
|
|
|
86
|
-
wi =
|
|
177
|
+
wi = particle_invmass[tid]
|
|
87
178
|
if wi == 0.0:
|
|
88
179
|
return
|
|
89
180
|
|
|
90
|
-
|
|
91
|
-
v_new = particle_v_new[tid]
|
|
92
|
-
x_old = particle_x_old[tid]
|
|
181
|
+
x = particle_x_old[tid]
|
|
93
182
|
v_old = particle_v_old[tid]
|
|
183
|
+
v_new = particle_v_new[tid]
|
|
94
184
|
|
|
95
185
|
n = wp.vec3(ground[0], ground[1], ground[2])
|
|
96
|
-
c = wp.dot(n,
|
|
186
|
+
c = wp.dot(n, x) + ground[3] - particle_radius[tid]
|
|
97
187
|
|
|
98
|
-
if c >
|
|
188
|
+
if c > particle_ka:
|
|
99
189
|
return
|
|
100
190
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
dv = n * wp.max(-rel_vel_new + wp.max(-restitution * rel_vel_old, 0.0), 0.0)
|
|
191
|
+
vn = wp.dot(n, v_old)
|
|
192
|
+
vn_new = wp.dot(n, v_new)
|
|
104
193
|
|
|
105
|
-
|
|
194
|
+
if vn < 0.0:
|
|
195
|
+
dv = n * (-vn_new + wp.max(-restitution * vn, 0.0))
|
|
196
|
+
wp.atomic_add(particle_v_out, tid, dv)
|
|
106
197
|
|
|
107
198
|
|
|
108
199
|
@wp.kernel
|
|
@@ -209,7 +300,7 @@ def solve_particle_shape_contacts(
|
|
|
209
300
|
delta_f = wp.normalize(vt) * lambda_f
|
|
210
301
|
delta_total = (delta_f - delta_n) / denom * relaxation
|
|
211
302
|
|
|
212
|
-
wp.atomic_add(delta, particle_index, delta_total)
|
|
303
|
+
wp.atomic_add(delta, particle_index, w1 * delta_total)
|
|
213
304
|
|
|
214
305
|
if body_index >= 0:
|
|
215
306
|
delta_t = wp.cross(r, delta_total)
|
|
@@ -280,7 +371,7 @@ def solve_particle_particle_contacts(
|
|
|
280
371
|
delta_f = wp.normalize(vt) * lambda_f
|
|
281
372
|
delta += (delta_f - delta_n) / denom
|
|
282
373
|
|
|
283
|
-
wp.atomic_add(deltas, i, delta * relaxation)
|
|
374
|
+
wp.atomic_add(deltas, i, delta * w1 * relaxation)
|
|
284
375
|
|
|
285
376
|
|
|
286
377
|
@wp.kernel
|
|
@@ -334,11 +425,11 @@ def solve_springs(
|
|
|
334
425
|
if denom <= 0.0 or ke <= 0.0 or kd < 0.0:
|
|
335
426
|
return
|
|
336
427
|
|
|
337
|
-
alpha= 1.0 / (ke * dt * dt)
|
|
428
|
+
alpha = 1.0 / (ke * dt * dt)
|
|
338
429
|
gamma = kd / (ke * dt)
|
|
339
430
|
|
|
340
|
-
grad_c_dot_v = dt * wp.dot(grad_c_xi, vij)
|
|
341
|
-
dlambda = -1.0 * (c + alpha* lambdas[tid] + gamma * grad_c_dot_v) / ((1.0 + gamma) * denom + alpha)
|
|
431
|
+
grad_c_dot_v = dt * wp.dot(grad_c_xi, vij) # Note: dt because from the paper we want x_i - x^n, not v...
|
|
432
|
+
dlambda = -1.0 * (c + alpha * lambdas[tid] + gamma * grad_c_dot_v) / ((1.0 + gamma) * denom + alpha)
|
|
342
433
|
|
|
343
434
|
dxi = wi * dlambda * grad_c_xi
|
|
344
435
|
dxj = wj * dlambda * grad_c_xj
|
|
@@ -420,7 +511,12 @@ def bending_constraint(
|
|
|
420
511
|
grad_x3 = (n1 * wp.dot(x1 - x4, e_hat) + n2 * wp.dot(x2 - x4, e_hat)) * derivative_flip
|
|
421
512
|
grad_x4 = (n1 * wp.dot(x3 - x1, e_hat) + n2 * wp.dot(x3 - x2, e_hat)) * derivative_flip
|
|
422
513
|
c = angle - rest_angle
|
|
423
|
-
denominator =
|
|
514
|
+
denominator = (
|
|
515
|
+
w1 * wp.length_sq(grad_x1)
|
|
516
|
+
+ w2 * wp.length_sq(grad_x2)
|
|
517
|
+
+ w3 * wp.length_sq(grad_x3)
|
|
518
|
+
+ w4 * wp.length_sq(grad_x4)
|
|
519
|
+
)
|
|
424
520
|
|
|
425
521
|
# Note strict inequality for damping -- 0 damping is ok
|
|
426
522
|
if denominator <= 0.0 or ke <= 0.0 or kd < 0.0:
|
|
@@ -448,6 +544,184 @@ def bending_constraint(
|
|
|
448
544
|
|
|
449
545
|
@wp.kernel
|
|
450
546
|
def solve_tetrahedra(
|
|
547
|
+
x: wp.array(dtype=wp.vec3),
|
|
548
|
+
v: wp.array(dtype=wp.vec3),
|
|
549
|
+
inv_mass: wp.array(dtype=float),
|
|
550
|
+
indices: wp.array(dtype=int, ndim=2),
|
|
551
|
+
rest_matrix: wp.array(dtype=wp.mat33),
|
|
552
|
+
activation: wp.array(dtype=float),
|
|
553
|
+
materials: wp.array(dtype=float, ndim=2),
|
|
554
|
+
dt: float,
|
|
555
|
+
relaxation: float,
|
|
556
|
+
delta: wp.array(dtype=wp.vec3),
|
|
557
|
+
):
|
|
558
|
+
tid = wp.tid()
|
|
559
|
+
|
|
560
|
+
i = indices[tid, 0]
|
|
561
|
+
j = indices[tid, 1]
|
|
562
|
+
k = indices[tid, 2]
|
|
563
|
+
l = indices[tid, 3]
|
|
564
|
+
|
|
565
|
+
act = activation[tid]
|
|
566
|
+
|
|
567
|
+
k_mu = materials[tid, 0]
|
|
568
|
+
k_lambda = materials[tid, 1]
|
|
569
|
+
k_damp = materials[tid, 2]
|
|
570
|
+
|
|
571
|
+
x0 = x[i]
|
|
572
|
+
x1 = x[j]
|
|
573
|
+
x2 = x[k]
|
|
574
|
+
x3 = x[l]
|
|
575
|
+
|
|
576
|
+
v0 = v[i]
|
|
577
|
+
v1 = v[j]
|
|
578
|
+
v2 = v[k]
|
|
579
|
+
v3 = v[l]
|
|
580
|
+
|
|
581
|
+
w0 = inv_mass[i]
|
|
582
|
+
w1 = inv_mass[j]
|
|
583
|
+
w2 = inv_mass[k]
|
|
584
|
+
w3 = inv_mass[l]
|
|
585
|
+
|
|
586
|
+
x10 = x1 - x0
|
|
587
|
+
x20 = x2 - x0
|
|
588
|
+
x30 = x3 - x0
|
|
589
|
+
|
|
590
|
+
v10 = v1 - v0
|
|
591
|
+
v20 = v2 - v0
|
|
592
|
+
v30 = v3 - v0
|
|
593
|
+
|
|
594
|
+
Ds = wp.mat33(x10, x20, x30)
|
|
595
|
+
Dm = rest_matrix[tid]
|
|
596
|
+
inv_QT = wp.transpose(Dm)
|
|
597
|
+
|
|
598
|
+
inv_rest_volume = wp.determinant(Dm) * 6.0
|
|
599
|
+
rest_volume = 1.0 / inv_rest_volume
|
|
600
|
+
|
|
601
|
+
# F = Xs*Xm^-1
|
|
602
|
+
F = Ds * Dm
|
|
603
|
+
|
|
604
|
+
f1 = wp.vec3(F[0, 0], F[1, 0], F[2, 0])
|
|
605
|
+
f2 = wp.vec3(F[0, 1], F[1, 1], F[2, 1])
|
|
606
|
+
f3 = wp.vec3(F[0, 2], F[1, 2], F[2, 2])
|
|
607
|
+
|
|
608
|
+
tr = wp.dot(f1, f1) + wp.dot(f2, f2) + wp.dot(f3, f3)
|
|
609
|
+
|
|
610
|
+
C = float(0.0)
|
|
611
|
+
dC = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
612
|
+
compliance = float(0.0)
|
|
613
|
+
|
|
614
|
+
stretching_compliance = relaxation
|
|
615
|
+
volume_compliance = relaxation
|
|
616
|
+
|
|
617
|
+
num_terms = 2
|
|
618
|
+
for term in range(0, num_terms):
|
|
619
|
+
|
|
620
|
+
if term == 0:
|
|
621
|
+
# deviatoric, stable
|
|
622
|
+
C = tr - 3.0
|
|
623
|
+
dC = F * 2.0
|
|
624
|
+
compliance = stretching_compliance
|
|
625
|
+
elif term == 1:
|
|
626
|
+
# volume conservation
|
|
627
|
+
C = wp.determinant(F) - 1.0
|
|
628
|
+
dC = wp.mat33(wp.cross(f2, f3), wp.cross(f3, f1), wp.cross(f1, f2))
|
|
629
|
+
compliance = volume_compliance
|
|
630
|
+
|
|
631
|
+
if C != 0.0:
|
|
632
|
+
|
|
633
|
+
dP = dC * inv_QT
|
|
634
|
+
grad1 = wp.vec3(dP[0][0], dP[1][0], dP[2][0])
|
|
635
|
+
grad2 = wp.vec3(dP[0][1], dP[1][1], dP[2][1])
|
|
636
|
+
grad3 = wp.vec3(dP[0][2], dP[1][2], dP[2][2])
|
|
637
|
+
grad0 = -grad1 - grad2 - grad3
|
|
638
|
+
|
|
639
|
+
w = (
|
|
640
|
+
wp.dot(grad0, grad0) * w0
|
|
641
|
+
+ wp.dot(grad1, grad1) * w1
|
|
642
|
+
+ wp.dot(grad2, grad2) * w2
|
|
643
|
+
+ wp.dot(grad3, grad3) * w3
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
if w > 0.0:
|
|
647
|
+
alpha = compliance / dt / dt
|
|
648
|
+
if inv_rest_volume > 0.0:
|
|
649
|
+
alpha *= inv_rest_volume
|
|
650
|
+
dlambda = -C / (w + alpha)
|
|
651
|
+
|
|
652
|
+
wp.atomic_add(delta, i, w0 * dlambda * grad0)
|
|
653
|
+
wp.atomic_add(delta, j, w1 * dlambda * grad1)
|
|
654
|
+
wp.atomic_add(delta, k, w2 * dlambda * grad2)
|
|
655
|
+
wp.atomic_add(delta, l, w3 * dlambda * grad3)
|
|
656
|
+
# wp.atomic_add(particle.num_corr, id0, 1)
|
|
657
|
+
# wp.atomic_add(particle.num_corr, id1, 1)
|
|
658
|
+
# wp.atomic_add(particle.num_corr, id2, 1)
|
|
659
|
+
# wp.atomic_add(particle.num_corr, id3, 1)
|
|
660
|
+
|
|
661
|
+
# C_Spherical
|
|
662
|
+
# r_s = wp.sqrt(wp.dot(f1, f1) + wp.dot(f2, f2) + wp.dot(f3, f3))
|
|
663
|
+
# r_s_inv = 1.0/r_s
|
|
664
|
+
# C = r_s - wp.sqrt(3.0)
|
|
665
|
+
# dCdx = F*wp.transpose(Dm)*r_s_inv
|
|
666
|
+
# alpha = 1.0
|
|
667
|
+
|
|
668
|
+
# C_D
|
|
669
|
+
# r_s = wp.sqrt(wp.dot(f1, f1) + wp.dot(f2, f2) + wp.dot(f3, f3))
|
|
670
|
+
# C = r_s*r_s - 3.0
|
|
671
|
+
# dCdx = F*wp.transpose(Dm)*2.0
|
|
672
|
+
# alpha = 1.0
|
|
673
|
+
|
|
674
|
+
# grad1 = wp.vec3(dCdx[0, 0], dCdx[1, 0], dCdx[2, 0])
|
|
675
|
+
# grad2 = wp.vec3(dCdx[0, 1], dCdx[1, 1], dCdx[2, 1])
|
|
676
|
+
# grad3 = wp.vec3(dCdx[0, 2], dCdx[1, 2], dCdx[2, 2])
|
|
677
|
+
# grad0 = (grad1 + grad2 + grad3) * (0.0 - 1.0)
|
|
678
|
+
|
|
679
|
+
# denom = (
|
|
680
|
+
# wp.dot(grad0, grad0) * w0 + wp.dot(grad1, grad1) * w1 + wp.dot(grad2, grad2) * w2 + wp.dot(grad3, grad3) * w3
|
|
681
|
+
# )
|
|
682
|
+
# multiplier = C / (denom + 1.0 / (k_mu * dt * dt * rest_volume))
|
|
683
|
+
|
|
684
|
+
# delta0 = grad0 * multiplier
|
|
685
|
+
# delta1 = grad1 * multiplier
|
|
686
|
+
# delta2 = grad2 * multiplier
|
|
687
|
+
# delta3 = grad3 * multiplier
|
|
688
|
+
|
|
689
|
+
# # hydrostatic part
|
|
690
|
+
# J = wp.determinant(F)
|
|
691
|
+
|
|
692
|
+
# C_vol = J - alpha
|
|
693
|
+
# # dCdx = wp.mat33(wp.cross(f2, f3), wp.cross(f3, f1), wp.cross(f1, f2))*wp.transpose(Dm)
|
|
694
|
+
|
|
695
|
+
# # grad1 = wp.vec3(dCdx[0,0], dCdx[1,0], dCdx[2,0])
|
|
696
|
+
# # grad2 = wp.vec3(dCdx[0,1], dCdx[1,1], dCdx[2,1])
|
|
697
|
+
# # grad3 = wp.vec3(dCdx[0,2], dCdx[1,2], dCdx[2,2])
|
|
698
|
+
# # grad0 = (grad1 + grad2 + grad3)*(0.0 - 1.0)
|
|
699
|
+
|
|
700
|
+
# s = inv_rest_volume / 6.0
|
|
701
|
+
# grad1 = wp.cross(x20, x30) * s
|
|
702
|
+
# grad2 = wp.cross(x30, x10) * s
|
|
703
|
+
# grad3 = wp.cross(x10, x20) * s
|
|
704
|
+
# grad0 = -(grad1 + grad2 + grad3)
|
|
705
|
+
|
|
706
|
+
# denom = (
|
|
707
|
+
# wp.dot(grad0, grad0) * w0 + wp.dot(grad1, grad1) * w1 + wp.dot(grad2, grad2) * w2 + wp.dot(grad3, grad3) * w3
|
|
708
|
+
# )
|
|
709
|
+
# multiplier = C_vol / (denom + 1.0 / (k_lambda * dt * dt * rest_volume))
|
|
710
|
+
|
|
711
|
+
# delta0 += grad0 * multiplier
|
|
712
|
+
# delta1 += grad1 * multiplier
|
|
713
|
+
# delta2 += grad2 * multiplier
|
|
714
|
+
# delta3 += grad3 * multiplier
|
|
715
|
+
|
|
716
|
+
# # # apply forces
|
|
717
|
+
# # wp.atomic_sub(delta, i, delta0 * w0 * relaxation)
|
|
718
|
+
# # wp.atomic_sub(delta, j, delta1 * w1 * relaxation)
|
|
719
|
+
# # wp.atomic_sub(delta, k, delta2 * w2 * relaxation)
|
|
720
|
+
# # wp.atomic_sub(delta, l, delta3 * w3 * relaxation)
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
@wp.kernel
|
|
724
|
+
def solve_tetrahedra2(
|
|
451
725
|
x: wp.array(dtype=wp.vec3),
|
|
452
726
|
v: wp.array(dtype=wp.vec3),
|
|
453
727
|
inv_mass: wp.array(dtype=float),
|
|
@@ -660,21 +934,22 @@ def apply_body_deltas(
|
|
|
660
934
|
|
|
661
935
|
weight = 1.0
|
|
662
936
|
if constraint_inv_weights:
|
|
663
|
-
|
|
664
|
-
|
|
937
|
+
inv_weight = constraint_inv_weights[tid]
|
|
938
|
+
if inv_weight > 0.0:
|
|
939
|
+
weight = 1.0 / inv_weight
|
|
665
940
|
|
|
666
941
|
dp = wp.spatial_bottom(delta) * (inv_m * weight)
|
|
667
942
|
dq = wp.spatial_top(delta) * weight
|
|
668
943
|
dq = wp.quat_rotate(q0, inv_I * wp.quat_rotate_inv(q0, dq))
|
|
669
944
|
|
|
670
945
|
# update orientation
|
|
671
|
-
q1 = q0 + 0.5 * wp.quat(dq * dt
|
|
946
|
+
q1 = q0 + 0.5 * wp.quat(dq * dt, 0.0) * q0
|
|
672
947
|
q1 = wp.normalize(q1)
|
|
673
948
|
|
|
674
949
|
# update position
|
|
675
950
|
com = body_com[tid]
|
|
676
951
|
x_com = p0 + wp.quat_rotate(q0, com)
|
|
677
|
-
p1 = x_com + dp * dt
|
|
952
|
+
p1 = x_com + dp * dt
|
|
678
953
|
p1 -= wp.quat_rotate(q1, com)
|
|
679
954
|
|
|
680
955
|
q_out[tid] = wp.transform(p1, q1)
|
|
@@ -683,23 +958,28 @@ def apply_body_deltas(
|
|
|
683
958
|
w0 = wp.spatial_top(qd_in[tid])
|
|
684
959
|
|
|
685
960
|
# update linear and angular velocity
|
|
686
|
-
v1 = v0 + dp
|
|
961
|
+
v1 = v0 + dp
|
|
687
962
|
# angular part (compute in body frame)
|
|
688
|
-
wb = wp.quat_rotate_inv(q0, w0 + dq
|
|
963
|
+
wb = wp.quat_rotate_inv(q0, w0 + dq)
|
|
689
964
|
tb = -wp.cross(wb, body_I[tid] * wb) # coriolis forces
|
|
690
965
|
w1 = wp.quat_rotate(q0, wb + inv_I * tb * dt)
|
|
691
966
|
|
|
967
|
+
# XXX this improves gradient stability
|
|
968
|
+
if wp.length(v1) < 1e-4:
|
|
969
|
+
v1 = wp.vec3(0.0)
|
|
970
|
+
if wp.length(w1) < 1e-4:
|
|
971
|
+
w1 = wp.vec3(0.0)
|
|
972
|
+
|
|
692
973
|
qd_out[tid] = wp.spatial_vector(w1, v1)
|
|
693
974
|
|
|
694
975
|
|
|
695
976
|
@wp.kernel
|
|
696
977
|
def apply_body_delta_velocities(
|
|
697
|
-
qd_in: wp.array(dtype=wp.spatial_vector),
|
|
698
978
|
deltas: wp.array(dtype=wp.spatial_vector),
|
|
699
979
|
qd_out: wp.array(dtype=wp.spatial_vector),
|
|
700
980
|
):
|
|
701
981
|
tid = wp.tid()
|
|
702
|
-
qd_out
|
|
982
|
+
wp.atomic_add(qd_out, tid, deltas[tid])
|
|
703
983
|
|
|
704
984
|
|
|
705
985
|
@wp.kernel
|
|
@@ -716,6 +996,7 @@ def apply_joint_torques(
|
|
|
716
996
|
joint_axis_start: wp.array(dtype=int),
|
|
717
997
|
joint_axis_dim: wp.array(dtype=int, ndim=2),
|
|
718
998
|
joint_axis: wp.array(dtype=wp.vec3),
|
|
999
|
+
joint_axis_mode: wp.array(dtype=int),
|
|
719
1000
|
joint_act: wp.array(dtype=float),
|
|
720
1001
|
body_f: wp.array(dtype=wp.spatial_vector),
|
|
721
1002
|
):
|
|
@@ -753,9 +1034,9 @@ def apply_joint_torques(
|
|
|
753
1034
|
com_c = body_com[id_c]
|
|
754
1035
|
r_c = wp.transform_get_translation(X_wc) - wp.transform_point(pose_c, com_c)
|
|
755
1036
|
|
|
756
|
-
# local joint rotations
|
|
757
|
-
q_p = wp.transform_get_rotation(X_wp)
|
|
758
|
-
q_c = wp.transform_get_rotation(X_wc)
|
|
1037
|
+
# # local joint rotations
|
|
1038
|
+
# q_p = wp.transform_get_rotation(X_wp)
|
|
1039
|
+
# q_c = wp.transform_get_rotation(X_wc)
|
|
759
1040
|
|
|
760
1041
|
# joint properties (for 1D joints)
|
|
761
1042
|
q_start = joint_q_start[tid]
|
|
@@ -770,15 +1051,19 @@ def apply_joint_torques(
|
|
|
770
1051
|
|
|
771
1052
|
# handle angular constraints
|
|
772
1053
|
if type == wp.sim.JOINT_REVOLUTE:
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1054
|
+
mode = joint_axis_mode[axis_start]
|
|
1055
|
+
if mode == wp.sim.JOINT_MODE_FORCE:
|
|
1056
|
+
axis = joint_axis[axis_start]
|
|
1057
|
+
act = joint_act[qd_start]
|
|
1058
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1059
|
+
t_total += act * a_p
|
|
777
1060
|
elif type == wp.sim.JOINT_PRISMATIC:
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1061
|
+
mode = joint_axis_mode[axis_start]
|
|
1062
|
+
if mode == wp.sim.JOINT_MODE_FORCE:
|
|
1063
|
+
axis = joint_axis[axis_start]
|
|
1064
|
+
act = joint_act[qd_start]
|
|
1065
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1066
|
+
f_total += act * a_p
|
|
782
1067
|
elif type == wp.sim.JOINT_COMPOUND:
|
|
783
1068
|
# q_off = wp.transform_get_rotation(X_cj)
|
|
784
1069
|
# q_pc = wp.quat_inverse(q_off)*wp.quat_inverse(q_p)*q_c*q_off
|
|
@@ -799,12 +1084,15 @@ def apply_joint_torques(
|
|
|
799
1084
|
# t_total += joint_act[qd_start+1] * wp.quat_rotate(q_w, axis_1)
|
|
800
1085
|
# t_total += joint_act[qd_start+2] * wp.quat_rotate(q_w, axis_2)
|
|
801
1086
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1087
|
+
if joint_axis_mode[axis_start + 0] == wp.sim.JOINT_MODE_FORCE:
|
|
1088
|
+
axis_0 = joint_axis[axis_start + 0]
|
|
1089
|
+
t_total += joint_act[qd_start + 0] * wp.transform_vector(X_wp, axis_0)
|
|
1090
|
+
if joint_axis_mode[axis_start + 1] == wp.sim.JOINT_MODE_FORCE:
|
|
1091
|
+
axis_1 = joint_axis[axis_start + 1]
|
|
1092
|
+
t_total += joint_act[qd_start + 1] * wp.transform_vector(X_wp, axis_1)
|
|
1093
|
+
if joint_axis_mode[axis_start + 2] == wp.sim.JOINT_MODE_FORCE:
|
|
1094
|
+
axis_2 = joint_axis[axis_start + 2]
|
|
1095
|
+
t_total += joint_act[qd_start + 2] * wp.transform_vector(X_wp, axis_2)
|
|
808
1096
|
|
|
809
1097
|
elif type == wp.sim.JOINT_UNIVERSAL:
|
|
810
1098
|
# q_off = wp.transform_get_rotation(X_cj)
|
|
@@ -828,63 +1116,71 @@ def apply_joint_torques(
|
|
|
828
1116
|
# t_total += joint_act[qd_start+0] * wp.quat_rotate(q_w, axis_0)
|
|
829
1117
|
# t_total += joint_act[qd_start+1] * wp.quat_rotate(q_w, axis_1)
|
|
830
1118
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1119
|
+
if joint_axis_mode[axis_start + 0] == wp.sim.JOINT_MODE_FORCE:
|
|
1120
|
+
axis_0 = joint_axis[axis_start + 0]
|
|
1121
|
+
t_total += joint_act[qd_start + 0] * wp.transform_vector(X_wp, axis_0)
|
|
1122
|
+
if joint_axis_mode[axis_start + 1] == wp.sim.JOINT_MODE_FORCE:
|
|
1123
|
+
axis_1 = joint_axis[axis_start + 1]
|
|
1124
|
+
t_total += joint_act[qd_start + 1] * wp.transform_vector(X_wp, axis_1)
|
|
835
1125
|
|
|
836
1126
|
elif type == wp.sim.JOINT_D6:
|
|
837
1127
|
# unroll for loop to ensure joint actions remain differentiable
|
|
838
1128
|
# (since differentiating through a dynamic for loop that updates a local variable is not supported)
|
|
839
1129
|
|
|
840
1130
|
if lin_axis_count > 0:
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
1131
|
+
if joint_axis_mode[axis_start + 0] == wp.sim.JOINT_MODE_FORCE:
|
|
1132
|
+
axis = joint_axis[axis_start + 0]
|
|
1133
|
+
act = joint_act[qd_start + 0]
|
|
1134
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1135
|
+
f_total += act * a_p
|
|
845
1136
|
if lin_axis_count > 1:
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1137
|
+
if joint_axis_mode[axis_start + 1] == wp.sim.JOINT_MODE_FORCE:
|
|
1138
|
+
axis = joint_axis[axis_start + 1]
|
|
1139
|
+
act = joint_act[qd_start + 1]
|
|
1140
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1141
|
+
f_total += act * a_p
|
|
850
1142
|
if lin_axis_count > 2:
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1143
|
+
if joint_axis_mode[axis_start + 2] == wp.sim.JOINT_MODE_FORCE:
|
|
1144
|
+
axis = joint_axis[axis_start + 2]
|
|
1145
|
+
act = joint_act[qd_start + 2]
|
|
1146
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1147
|
+
f_total += act * a_p
|
|
855
1148
|
|
|
856
1149
|
if ang_axis_count > 0:
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1150
|
+
if joint_axis_mode[axis_start + lin_axis_count + 0] == wp.sim.JOINT_MODE_FORCE:
|
|
1151
|
+
axis = joint_axis[axis_start + lin_axis_count + 0]
|
|
1152
|
+
act = joint_act[qd_start + lin_axis_count + 0]
|
|
1153
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1154
|
+
t_total += act * a_p
|
|
861
1155
|
if ang_axis_count > 1:
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1156
|
+
if joint_axis_mode[axis_start + lin_axis_count + 1] == wp.sim.JOINT_MODE_FORCE:
|
|
1157
|
+
axis = joint_axis[axis_start + lin_axis_count + 1]
|
|
1158
|
+
act = joint_act[qd_start + lin_axis_count + 1]
|
|
1159
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1160
|
+
t_total += act * a_p
|
|
866
1161
|
if ang_axis_count > 2:
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1162
|
+
if joint_axis_mode[axis_start + lin_axis_count + 2] == wp.sim.JOINT_MODE_FORCE:
|
|
1163
|
+
axis = joint_axis[axis_start + lin_axis_count + 2]
|
|
1164
|
+
act = joint_act[qd_start + lin_axis_count + 2]
|
|
1165
|
+
a_p = wp.transform_vector(X_wp, axis)
|
|
1166
|
+
t_total += act * a_p
|
|
871
1167
|
|
|
872
1168
|
else:
|
|
873
1169
|
print("joint type not handled in apply_joint_torques")
|
|
874
1170
|
|
|
875
1171
|
# write forces
|
|
876
1172
|
if id_p >= 0:
|
|
877
|
-
wp.
|
|
878
|
-
wp.
|
|
1173
|
+
wp.atomic_sub(body_f, id_p, wp.spatial_vector(t_total + wp.cross(r_p, f_total), f_total))
|
|
1174
|
+
wp.atomic_add(body_f, id_c, wp.spatial_vector(t_total + wp.cross(r_c, f_total), f_total))
|
|
879
1175
|
|
|
880
1176
|
|
|
881
1177
|
@wp.func
|
|
882
|
-
def update_joint_axis_mode(mode: wp.
|
|
1178
|
+
def update_joint_axis_mode(mode: wp.int32, axis: wp.vec3, input_axis_mode: wp.vec3i):
|
|
883
1179
|
# update the 3D axis mode flags given the axis vector and mode of this axis
|
|
884
|
-
mode_x = wp.max(wp.
|
|
885
|
-
mode_y = wp.max(wp.
|
|
886
|
-
mode_z = wp.max(wp.
|
|
887
|
-
return wp.
|
|
1180
|
+
mode_x = wp.max(wp.int32(wp.nonzero(axis[0])) * mode, input_axis_mode[0])
|
|
1181
|
+
mode_y = wp.max(wp.int32(wp.nonzero(axis[1])) * mode, input_axis_mode[1])
|
|
1182
|
+
mode_z = wp.max(wp.int32(wp.nonzero(axis[2])) * mode, input_axis_mode[2])
|
|
1183
|
+
return wp.vec3i(mode_x, mode_y, mode_z)
|
|
888
1184
|
|
|
889
1185
|
|
|
890
1186
|
@wp.func
|
|
@@ -926,8 +1222,99 @@ def update_joint_axis_target_ke_kd(
|
|
|
926
1222
|
)
|
|
927
1223
|
|
|
928
1224
|
|
|
1225
|
+
@wp.func
|
|
1226
|
+
def compute_linear_correction_3d(
|
|
1227
|
+
dx: wp.vec3,
|
|
1228
|
+
r1: wp.vec3,
|
|
1229
|
+
r2: wp.vec3,
|
|
1230
|
+
tf1: wp.transform,
|
|
1231
|
+
tf2: wp.transform,
|
|
1232
|
+
m_inv1: float,
|
|
1233
|
+
m_inv2: float,
|
|
1234
|
+
I_inv1: wp.mat33,
|
|
1235
|
+
I_inv2: wp.mat33,
|
|
1236
|
+
lambda_in: float,
|
|
1237
|
+
compliance: float,
|
|
1238
|
+
damping: float,
|
|
1239
|
+
dt: float,
|
|
1240
|
+
) -> float:
|
|
1241
|
+
|
|
1242
|
+
c = wp.length(dx)
|
|
1243
|
+
if c == 0.0:
|
|
1244
|
+
# print("c == 0.0 in positional correction")
|
|
1245
|
+
return 0.0
|
|
1246
|
+
|
|
1247
|
+
n = wp.normalize(dx)
|
|
1248
|
+
|
|
1249
|
+
q1 = wp.transform_get_rotation(tf1)
|
|
1250
|
+
q2 = wp.transform_get_rotation(tf2)
|
|
1251
|
+
|
|
1252
|
+
# Eq. 2-3 (make sure to project into the frame of the body)
|
|
1253
|
+
r1xn = wp.quat_rotate_inv(q1, wp.cross(r1, n))
|
|
1254
|
+
r2xn = wp.quat_rotate_inv(q2, wp.cross(r2, n))
|
|
1255
|
+
|
|
1256
|
+
w1 = m_inv1 + wp.dot(r1xn, I_inv1 * r1xn)
|
|
1257
|
+
w2 = m_inv2 + wp.dot(r2xn, I_inv2 * r2xn)
|
|
1258
|
+
w = w1 + w2
|
|
1259
|
+
if w == 0.0:
|
|
1260
|
+
return 0.0
|
|
1261
|
+
alpha = compliance
|
|
1262
|
+
gamma = compliance * damping
|
|
1263
|
+
|
|
1264
|
+
# Eq. 4-5
|
|
1265
|
+
d_lambda = -c - alpha * lambda_in
|
|
1266
|
+
# TODO consider damping for velocity correction?
|
|
1267
|
+
# delta_lambda = -(err + alpha * lambda_in + gamma * derr)
|
|
1268
|
+
if w + alpha > 0.0:
|
|
1269
|
+
d_lambda /= w * (dt + gamma) + alpha / dt
|
|
1270
|
+
|
|
1271
|
+
return d_lambda
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
@wp.func
|
|
1275
|
+
def compute_angular_correction_3d(
|
|
1276
|
+
corr: wp.vec3,
|
|
1277
|
+
q1: wp.quat,
|
|
1278
|
+
q2: wp.quat,
|
|
1279
|
+
m_inv1: float,
|
|
1280
|
+
m_inv2: float,
|
|
1281
|
+
I_inv1: wp.mat33,
|
|
1282
|
+
I_inv2: wp.mat33,
|
|
1283
|
+
alpha_tilde: float,
|
|
1284
|
+
# lambda_prev: float,
|
|
1285
|
+
relaxation: float,
|
|
1286
|
+
dt: float,
|
|
1287
|
+
):
|
|
1288
|
+
# compute and apply the correction impulse for an angular constraint
|
|
1289
|
+
theta = wp.length(corr)
|
|
1290
|
+
if theta == 0.0:
|
|
1291
|
+
return 0.0
|
|
1292
|
+
|
|
1293
|
+
n = wp.normalize(corr)
|
|
1294
|
+
|
|
1295
|
+
# project variables to body rest frame as they are in local matrix
|
|
1296
|
+
n1 = wp.quat_rotate_inv(q1, n)
|
|
1297
|
+
n2 = wp.quat_rotate_inv(q2, n)
|
|
1298
|
+
|
|
1299
|
+
# Eq. 11-12
|
|
1300
|
+
w1 = wp.dot(n1, I_inv1 * n1)
|
|
1301
|
+
w2 = wp.dot(n2, I_inv2 * n2)
|
|
1302
|
+
w = w1 + w2
|
|
1303
|
+
if w == 0.0:
|
|
1304
|
+
return 0.0
|
|
1305
|
+
|
|
1306
|
+
# Eq. 13-14
|
|
1307
|
+
lambda_prev = 0.0
|
|
1308
|
+
d_lambda = (-theta - alpha_tilde * lambda_prev) / (w * dt + alpha_tilde / dt)
|
|
1309
|
+
# TODO consider lambda_prev?
|
|
1310
|
+
# p = d_lambda * n * relaxation
|
|
1311
|
+
|
|
1312
|
+
# Eq. 15-16
|
|
1313
|
+
return d_lambda
|
|
1314
|
+
|
|
1315
|
+
|
|
929
1316
|
@wp.kernel
|
|
930
|
-
def
|
|
1317
|
+
def solve_simple_body_joints(
|
|
931
1318
|
body_q: wp.array(dtype=wp.transform),
|
|
932
1319
|
body_qd: wp.array(dtype=wp.spatial_vector),
|
|
933
1320
|
body_com: wp.array(dtype=wp.vec3),
|
|
@@ -943,7 +1330,7 @@ def solve_body_joints(
|
|
|
943
1330
|
joint_limit_upper: wp.array(dtype=float),
|
|
944
1331
|
joint_axis_start: wp.array(dtype=int),
|
|
945
1332
|
joint_axis_dim: wp.array(dtype=int, ndim=2),
|
|
946
|
-
joint_axis_mode: wp.array(dtype=
|
|
1333
|
+
joint_axis_mode: wp.array(dtype=int),
|
|
947
1334
|
joint_axis: wp.array(dtype=wp.vec3),
|
|
948
1335
|
joint_target: wp.array(dtype=float),
|
|
949
1336
|
joint_target_ke: wp.array(dtype=float),
|
|
@@ -958,7 +1345,17 @@ def solve_body_joints(
|
|
|
958
1345
|
tid = wp.tid()
|
|
959
1346
|
type = joint_type[tid]
|
|
960
1347
|
|
|
961
|
-
if joint_enabled[tid] == 0
|
|
1348
|
+
if joint_enabled[tid] == 0:
|
|
1349
|
+
return
|
|
1350
|
+
if type == wp.sim.JOINT_FREE:
|
|
1351
|
+
return
|
|
1352
|
+
if type == wp.sim.JOINT_COMPOUND:
|
|
1353
|
+
return
|
|
1354
|
+
if type == wp.sim.JOINT_UNIVERSAL:
|
|
1355
|
+
return
|
|
1356
|
+
if type == wp.sim.JOINT_DISTANCE:
|
|
1357
|
+
return
|
|
1358
|
+
if type == wp.sim.JOINT_D6:
|
|
962
1359
|
return
|
|
963
1360
|
|
|
964
1361
|
# rigid body indices of the child and parent
|
|
@@ -973,8 +1370,6 @@ def solve_body_joints(
|
|
|
973
1370
|
I_inv_p = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
974
1371
|
pose_p = X_pj
|
|
975
1372
|
com_p = wp.vec3(0.0)
|
|
976
|
-
vel_p = wp.vec3(0.0)
|
|
977
|
-
omega_p = wp.vec3(0.0)
|
|
978
1373
|
# parent transform and moment arm
|
|
979
1374
|
if id_p >= 0:
|
|
980
1375
|
pose_p = body_q[id_p]
|
|
@@ -982,8 +1377,7 @@ def solve_body_joints(
|
|
|
982
1377
|
com_p = body_com[id_p]
|
|
983
1378
|
m_inv_p = body_inv_m[id_p]
|
|
984
1379
|
I_inv_p = body_inv_I[id_p]
|
|
985
|
-
|
|
986
|
-
omega_p = wp.spatial_top(body_qd[id_p])
|
|
1380
|
+
r_p = wp.transform_get_translation(X_wp) - wp.transform_point(pose_p, com_p)
|
|
987
1381
|
|
|
988
1382
|
# child transform and moment arm
|
|
989
1383
|
pose_c = body_q[id_c]
|
|
@@ -991,8 +1385,7 @@ def solve_body_joints(
|
|
|
991
1385
|
com_c = body_com[id_c]
|
|
992
1386
|
m_inv_c = body_inv_m[id_c]
|
|
993
1387
|
I_inv_c = body_inv_I[id_c]
|
|
994
|
-
|
|
995
|
-
omega_c = wp.spatial_top(body_qd[id_c])
|
|
1388
|
+
r_c = wp.transform_get_translation(X_wc) - wp.transform_point(pose_c, com_c)
|
|
996
1389
|
|
|
997
1390
|
if m_inv_p == 0.0 and m_inv_c == 0.0:
|
|
998
1391
|
# connection between two immovable bodies
|
|
@@ -1013,32 +1406,358 @@ def solve_body_joints(
|
|
|
1013
1406
|
|
|
1014
1407
|
linear_compliance = joint_linear_compliance[tid]
|
|
1015
1408
|
angular_compliance = joint_angular_compliance[tid]
|
|
1409
|
+
damping = 0.0
|
|
1016
1410
|
|
|
1017
1411
|
axis_start = joint_axis_start[tid]
|
|
1018
|
-
|
|
1019
|
-
ang_axis_count = joint_axis_dim[tid, 1]
|
|
1412
|
+
mode = joint_axis_mode[axis_start]
|
|
1020
1413
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1414
|
+
# local joint rotations
|
|
1415
|
+
q_p = wp.transform_get_rotation(X_wp)
|
|
1416
|
+
q_c = wp.transform_get_rotation(X_wc)
|
|
1417
|
+
inertial_q_p = wp.transform_get_rotation(pose_p)
|
|
1418
|
+
inertial_q_c = wp.transform_get_rotation(pose_c)
|
|
1023
1419
|
|
|
1024
|
-
#
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1420
|
+
# joint properties (for 1D joints)
|
|
1421
|
+
axis = joint_axis[axis_start]
|
|
1422
|
+
|
|
1423
|
+
if type == wp.sim.JOINT_FIXED:
|
|
1424
|
+
limit_lower = 0.0
|
|
1425
|
+
limit_upper = 0.0
|
|
1426
|
+
else:
|
|
1427
|
+
limit_lower = joint_limit_lower[axis_start]
|
|
1428
|
+
limit_upper = joint_limit_upper[axis_start]
|
|
1429
|
+
|
|
1430
|
+
linear_alpha_tilde = linear_compliance / dt / dt
|
|
1431
|
+
angular_alpha_tilde = angular_compliance / dt / dt
|
|
1432
|
+
|
|
1433
|
+
# prevent division by zero
|
|
1434
|
+
# linear_alpha_tilde = wp.max(linear_alpha_tilde, 1e-6)
|
|
1435
|
+
# angular_alpha_tilde = wp.max(angular_alpha_tilde, 1e-6)
|
|
1436
|
+
|
|
1437
|
+
# accumulate constraint deltas
|
|
1438
|
+
lin_delta_p = wp.vec3(0.0)
|
|
1439
|
+
ang_delta_p = wp.vec3(0.0)
|
|
1440
|
+
lin_delta_c = wp.vec3(0.0)
|
|
1441
|
+
ang_delta_c = wp.vec3(0.0)
|
|
1442
|
+
|
|
1443
|
+
# handle angular constraints
|
|
1444
|
+
if type == wp.sim.JOINT_REVOLUTE:
|
|
1445
|
+
# align joint axes
|
|
1446
|
+
a_p = wp.quat_rotate(q_p, axis)
|
|
1447
|
+
a_c = wp.quat_rotate(q_c, axis)
|
|
1448
|
+
# Eq. 20
|
|
1449
|
+
corr = wp.cross(a_p, a_c)
|
|
1450
|
+
ncorr = wp.normalize(corr)
|
|
1451
|
+
|
|
1452
|
+
angular_relaxation = 0.2
|
|
1453
|
+
# angular_correction(
|
|
1454
|
+
# corr, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c,
|
|
1455
|
+
# angular_alpha_tilde, angular_relaxation, deltas, id_p, id_c)
|
|
1456
|
+
lambda_n = compute_angular_correction_3d(
|
|
1457
|
+
corr, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c, angular_alpha_tilde, damping, dt
|
|
1458
|
+
)
|
|
1459
|
+
lambda_n *= angular_relaxation
|
|
1460
|
+
ang_delta_p -= lambda_n * ncorr
|
|
1461
|
+
ang_delta_c += lambda_n * ncorr
|
|
1462
|
+
|
|
1463
|
+
# limit joint angles (Alg. 3)
|
|
1464
|
+
pi = 3.14159265359
|
|
1465
|
+
two_pi = 2.0 * pi
|
|
1466
|
+
if limit_lower > -two_pi or limit_upper < two_pi:
|
|
1467
|
+
# find a perpendicular vector to joint axis
|
|
1468
|
+
a = axis
|
|
1469
|
+
# https://math.stackexchange.com/a/3582461
|
|
1470
|
+
g = wp.sign(a[2])
|
|
1471
|
+
h = a[2] + g
|
|
1472
|
+
b = wp.vec3(g - a[0] * a[0] / h, -a[0] * a[1] / h, -a[0])
|
|
1473
|
+
c = wp.normalize(wp.cross(a, b))
|
|
1474
|
+
# b = c # TODO verify
|
|
1475
|
+
|
|
1476
|
+
# joint axis
|
|
1477
|
+
n = wp.quat_rotate(q_p, a)
|
|
1478
|
+
# the axes n1 and n2 are aligned with the two bodies
|
|
1479
|
+
n1 = wp.quat_rotate(q_p, b)
|
|
1480
|
+
n2 = wp.quat_rotate(q_c, b)
|
|
1481
|
+
|
|
1482
|
+
phi = wp.asin(wp.dot(wp.cross(n1, n2), n))
|
|
1483
|
+
# print("phi")
|
|
1484
|
+
# print(phi)
|
|
1485
|
+
if wp.dot(n1, n2) < 0.0:
|
|
1486
|
+
phi = pi - phi
|
|
1487
|
+
if phi > pi:
|
|
1488
|
+
phi -= two_pi
|
|
1489
|
+
if phi < -pi:
|
|
1490
|
+
phi += two_pi
|
|
1491
|
+
if phi < limit_lower or phi > limit_upper:
|
|
1492
|
+
phi = wp.clamp(phi, limit_lower, limit_upper)
|
|
1493
|
+
# print("clamped phi")
|
|
1494
|
+
# print(phi)
|
|
1495
|
+
# rot = wp.quat(phi, n[0], n[1], n[2])
|
|
1496
|
+
# rot = wp.quat(n, phi)
|
|
1497
|
+
rot = wp.quat_from_axis_angle(n, phi)
|
|
1498
|
+
n1 = wp.quat_rotate(rot, n1)
|
|
1499
|
+
corr = wp.cross(n1, n2)
|
|
1500
|
+
# print("corr")
|
|
1501
|
+
# print(corr)
|
|
1502
|
+
# TODO expose
|
|
1503
|
+
# angular_alpha_tilde = 0.0001 / dt / dt
|
|
1504
|
+
# angular_relaxation = 0.5
|
|
1505
|
+
# TODO fix this constraint
|
|
1506
|
+
# angular_correction(
|
|
1507
|
+
# corr, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c,
|
|
1508
|
+
# angular_alpha_tilde, angular_relaxation, deltas, id_p, id_c)
|
|
1509
|
+
lambda_n = compute_angular_correction_3d(
|
|
1510
|
+
corr,
|
|
1511
|
+
inertial_q_p,
|
|
1512
|
+
inertial_q_c,
|
|
1513
|
+
m_inv_p,
|
|
1514
|
+
m_inv_c,
|
|
1515
|
+
I_inv_p,
|
|
1516
|
+
I_inv_c,
|
|
1517
|
+
angular_alpha_tilde,
|
|
1518
|
+
damping,
|
|
1519
|
+
dt,
|
|
1520
|
+
)
|
|
1521
|
+
lambda_n *= angular_relaxation
|
|
1522
|
+
ncorr = wp.normalize(corr)
|
|
1523
|
+
ang_delta_p -= lambda_n * ncorr
|
|
1524
|
+
ang_delta_c += lambda_n * ncorr
|
|
1525
|
+
|
|
1526
|
+
# handle joint targets
|
|
1527
|
+
target_ke = joint_target_ke[axis_start]
|
|
1528
|
+
target_kd = joint_target_kd[axis_start]
|
|
1529
|
+
target = joint_target[axis_start]
|
|
1530
|
+
if target_ke > 0.0:
|
|
1531
|
+
# find a perpendicular vector to joint axis
|
|
1532
|
+
a = axis
|
|
1533
|
+
# https://math.stackexchange.com/a/3582461
|
|
1534
|
+
g = wp.sign(a[2])
|
|
1535
|
+
h = a[2] + g
|
|
1536
|
+
b = wp.vec3(g - a[0] * a[0] / h, -a[0] * a[1] / h, -a[0])
|
|
1537
|
+
c = wp.normalize(wp.cross(a, b))
|
|
1538
|
+
b = c
|
|
1539
|
+
|
|
1540
|
+
q = wp.quat_from_axis_angle(a_p, target)
|
|
1541
|
+
b_target = wp.quat_rotate(q, wp.quat_rotate(q_p, b))
|
|
1542
|
+
b2 = wp.quat_rotate(q_c, b)
|
|
1543
|
+
# Eq. 21
|
|
1544
|
+
d_target = wp.cross(b_target, b2)
|
|
1545
|
+
|
|
1546
|
+
target_compliance = 1.0 / target_ke # / dt / dt
|
|
1547
|
+
# angular_correction(
|
|
1548
|
+
# d_target, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c,
|
|
1549
|
+
# target_compliance, angular_relaxation, deltas, id_p, id_c)
|
|
1550
|
+
lambda_n = compute_angular_correction_3d(
|
|
1551
|
+
d_target, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c, target_compliance, damping, dt
|
|
1552
|
+
)
|
|
1553
|
+
lambda_n *= angular_relaxation
|
|
1554
|
+
ncorr = wp.normalize(d_target)
|
|
1555
|
+
# TODO fix
|
|
1556
|
+
ang_delta_p -= lambda_n * ncorr
|
|
1557
|
+
ang_delta_c += lambda_n * ncorr
|
|
1558
|
+
|
|
1559
|
+
if (type == wp.sim.JOINT_FIXED) or (type == wp.sim.JOINT_PRISMATIC):
|
|
1560
|
+
# align the mutual orientations of the two bodies
|
|
1561
|
+
# Eq. 18-19
|
|
1562
|
+
q = q_p * wp.quat_inverse(q_c)
|
|
1563
|
+
corr = -2.0 * wp.vec3(q[0], q[1], q[2])
|
|
1564
|
+
# angular_correction(
|
|
1565
|
+
# -corr, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c,
|
|
1566
|
+
# angular_alpha_tilde, angular_relaxation, deltas, id_p, id_c)
|
|
1567
|
+
lambda_n = compute_angular_correction_3d(
|
|
1568
|
+
corr, inertial_q_p, inertial_q_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c, angular_alpha_tilde, damping, dt
|
|
1569
|
+
)
|
|
1570
|
+
lambda_n *= angular_relaxation
|
|
1571
|
+
ncorr = wp.normalize(corr)
|
|
1572
|
+
ang_delta_p -= lambda_n * ncorr
|
|
1573
|
+
ang_delta_c += lambda_n * ncorr
|
|
1574
|
+
|
|
1575
|
+
# handle positional constraints
|
|
1576
|
+
|
|
1577
|
+
# joint connection points
|
|
1578
|
+
x_p = wp.transform_get_translation(X_wp)
|
|
1579
|
+
x_c = wp.transform_get_translation(X_wc)
|
|
1580
|
+
|
|
1581
|
+
# compute error between the joint attachment points on both bodies
|
|
1582
|
+
# delta x is the difference of point r_2 minus point r_1 (Fig. 3)
|
|
1583
|
+
dx = x_c - x_p
|
|
1584
|
+
|
|
1585
|
+
# rotate the error vector into the joint frame
|
|
1586
|
+
q_dx = q_p
|
|
1587
|
+
# q_dx = q_c
|
|
1588
|
+
# q_dx = wp.transform_get_rotation(pose_p)
|
|
1589
|
+
dx = wp.quat_rotate_inv(q_dx, dx)
|
|
1590
|
+
|
|
1591
|
+
lower_pos_limits = wp.vec3(0.0)
|
|
1592
|
+
upper_pos_limits = wp.vec3(0.0)
|
|
1593
|
+
if type == wp.sim.JOINT_PRISMATIC:
|
|
1594
|
+
lower_pos_limits = axis * limit_lower
|
|
1595
|
+
upper_pos_limits = axis * limit_upper
|
|
1596
|
+
|
|
1597
|
+
# compute linear constraint violations
|
|
1598
|
+
corr = wp.vec3(0.0)
|
|
1599
|
+
zero = wp.vec3(0.0)
|
|
1600
|
+
corr -= vec_leaky_min(zero, upper_pos_limits - dx)
|
|
1601
|
+
corr -= vec_leaky_max(zero, lower_pos_limits - dx)
|
|
1602
|
+
|
|
1603
|
+
# if (type == wp.sim.JOINT_PRISMATIC):
|
|
1604
|
+
# if mode == JOINT_MODE_TARGET_POSITION:
|
|
1605
|
+
# target = wp.clamp(target, limit_lower, limit_upper)
|
|
1606
|
+
# if target_ke > 0.0:
|
|
1607
|
+
# err = dx - target * axis
|
|
1608
|
+
# compliance = 1.0 / target_ke
|
|
1609
|
+
# damping = axis_damping[dim]
|
|
1610
|
+
# elif mode == JOINT_MODE_TARGET_VELOCITY:
|
|
1611
|
+
# if target_ke > 0.0:
|
|
1612
|
+
# err = (derr - target) * dt
|
|
1613
|
+
# compliance = 1.0 / target_ke
|
|
1614
|
+
# damping = axis_damping[dim]
|
|
1615
|
+
|
|
1616
|
+
# rotate correction vector into world frame
|
|
1617
|
+
corr = wp.quat_rotate(q_dx, corr)
|
|
1618
|
+
|
|
1619
|
+
lambda_in = 0.0
|
|
1620
|
+
linear_alpha = joint_linear_compliance[tid]
|
|
1621
|
+
lambda_n = compute_linear_correction_3d(
|
|
1622
|
+
corr, r_p, r_c, pose_p, pose_c, m_inv_p, m_inv_c, I_inv_p, I_inv_c, lambda_in, linear_alpha, damping, dt
|
|
1623
|
+
)
|
|
1624
|
+
lambda_n *= linear_relaxation
|
|
1625
|
+
n = wp.normalize(corr)
|
|
1626
|
+
|
|
1627
|
+
lin_delta_p -= n * lambda_n
|
|
1628
|
+
lin_delta_c += n * lambda_n
|
|
1629
|
+
ang_delta_p -= wp.cross(r_p, n) * lambda_n
|
|
1630
|
+
ang_delta_c += wp.cross(r_c, n) * lambda_n
|
|
1631
|
+
|
|
1632
|
+
if id_p >= 0:
|
|
1633
|
+
wp.atomic_add(deltas, id_p, wp.spatial_vector(ang_delta_p, lin_delta_p))
|
|
1634
|
+
if id_c >= 0:
|
|
1635
|
+
wp.atomic_add(deltas, id_c, wp.spatial_vector(ang_delta_c, lin_delta_c))
|
|
1636
|
+
|
|
1637
|
+
|
|
1638
|
+
@wp.kernel
|
|
1639
|
+
def solve_body_joints(
|
|
1640
|
+
body_q: wp.array(dtype=wp.transform),
|
|
1641
|
+
body_qd: wp.array(dtype=wp.spatial_vector),
|
|
1642
|
+
body_com: wp.array(dtype=wp.vec3),
|
|
1643
|
+
body_inv_m: wp.array(dtype=float),
|
|
1644
|
+
body_inv_I: wp.array(dtype=wp.mat33),
|
|
1645
|
+
joint_type: wp.array(dtype=int),
|
|
1646
|
+
joint_enabled: wp.array(dtype=int),
|
|
1647
|
+
joint_parent: wp.array(dtype=int),
|
|
1648
|
+
joint_child: wp.array(dtype=int),
|
|
1649
|
+
joint_X_p: wp.array(dtype=wp.transform),
|
|
1650
|
+
joint_X_c: wp.array(dtype=wp.transform),
|
|
1651
|
+
joint_limit_lower: wp.array(dtype=float),
|
|
1652
|
+
joint_limit_upper: wp.array(dtype=float),
|
|
1653
|
+
joint_axis_start: wp.array(dtype=int),
|
|
1654
|
+
joint_axis_dim: wp.array(dtype=int, ndim=2),
|
|
1655
|
+
joint_axis_mode: wp.array(dtype=int),
|
|
1656
|
+
joint_axis: wp.array(dtype=wp.vec3),
|
|
1657
|
+
joint_act: wp.array(dtype=float),
|
|
1658
|
+
joint_target_ke: wp.array(dtype=float),
|
|
1659
|
+
joint_target_kd: wp.array(dtype=float),
|
|
1660
|
+
joint_linear_compliance: wp.array(dtype=float),
|
|
1661
|
+
joint_angular_compliance: wp.array(dtype=float),
|
|
1662
|
+
angular_relaxation: float,
|
|
1663
|
+
linear_relaxation: float,
|
|
1664
|
+
dt: float,
|
|
1665
|
+
deltas: wp.array(dtype=wp.spatial_vector),
|
|
1666
|
+
):
|
|
1667
|
+
tid = wp.tid()
|
|
1668
|
+
type = joint_type[tid]
|
|
1669
|
+
|
|
1670
|
+
if joint_enabled[tid] == 0:
|
|
1671
|
+
return
|
|
1672
|
+
if type == wp.sim.JOINT_FREE:
|
|
1673
|
+
return
|
|
1674
|
+
# if type == wp.sim.JOINT_FIXED:
|
|
1675
|
+
# return
|
|
1676
|
+
# if type == wp.sim.JOINT_REVOLUTE:
|
|
1677
|
+
# return
|
|
1678
|
+
# if type == wp.sim.JOINT_PRISMATIC:
|
|
1679
|
+
# return
|
|
1680
|
+
# if type == wp.sim.JOINT_BALL:
|
|
1681
|
+
# return
|
|
1682
|
+
|
|
1683
|
+
# rigid body indices of the child and parent
|
|
1684
|
+
id_c = joint_child[tid]
|
|
1685
|
+
id_p = joint_parent[tid]
|
|
1686
|
+
|
|
1687
|
+
X_pj = joint_X_p[tid]
|
|
1688
|
+
X_cj = joint_X_c[tid]
|
|
1689
|
+
|
|
1690
|
+
X_wp = X_pj
|
|
1691
|
+
m_inv_p = 0.0
|
|
1692
|
+
I_inv_p = wp.mat33(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
1693
|
+
pose_p = X_pj
|
|
1694
|
+
com_p = wp.vec3(0.0)
|
|
1695
|
+
vel_p = wp.vec3(0.0)
|
|
1696
|
+
omega_p = wp.vec3(0.0)
|
|
1697
|
+
# parent transform and moment arm
|
|
1698
|
+
if id_p >= 0:
|
|
1699
|
+
pose_p = body_q[id_p]
|
|
1700
|
+
X_wp = pose_p * X_wp
|
|
1701
|
+
com_p = body_com[id_p]
|
|
1702
|
+
m_inv_p = body_inv_m[id_p]
|
|
1703
|
+
I_inv_p = body_inv_I[id_p]
|
|
1704
|
+
vel_p = wp.spatial_bottom(body_qd[id_p])
|
|
1705
|
+
omega_p = wp.spatial_top(body_qd[id_p])
|
|
1706
|
+
|
|
1707
|
+
# child transform and moment arm
|
|
1708
|
+
pose_c = body_q[id_c]
|
|
1709
|
+
X_wc = pose_c * X_cj
|
|
1710
|
+
com_c = body_com[id_c]
|
|
1711
|
+
m_inv_c = body_inv_m[id_c]
|
|
1712
|
+
I_inv_c = body_inv_I[id_c]
|
|
1713
|
+
vel_c = wp.spatial_bottom(body_qd[id_c])
|
|
1714
|
+
omega_c = wp.spatial_top(body_qd[id_c])
|
|
1715
|
+
|
|
1716
|
+
if m_inv_p == 0.0 and m_inv_c == 0.0:
|
|
1717
|
+
# connection between two immovable bodies
|
|
1718
|
+
return
|
|
1719
|
+
|
|
1720
|
+
# accumulate constraint deltas
|
|
1721
|
+
lin_delta_p = wp.vec3(0.0)
|
|
1722
|
+
ang_delta_p = wp.vec3(0.0)
|
|
1723
|
+
lin_delta_c = wp.vec3(0.0)
|
|
1724
|
+
ang_delta_c = wp.vec3(0.0)
|
|
1725
|
+
|
|
1726
|
+
rel_pose = wp.transform_inverse(X_wp) * X_wc
|
|
1727
|
+
rel_p = wp.transform_get_translation(rel_pose)
|
|
1728
|
+
|
|
1729
|
+
# joint connection points
|
|
1730
|
+
# x_p = wp.transform_get_translation(X_wp)
|
|
1731
|
+
x_c = wp.transform_get_translation(X_wc)
|
|
1732
|
+
|
|
1733
|
+
linear_compliance = joint_linear_compliance[tid]
|
|
1734
|
+
angular_compliance = joint_angular_compliance[tid]
|
|
1735
|
+
|
|
1736
|
+
axis_start = joint_axis_start[tid]
|
|
1737
|
+
lin_axis_count = joint_axis_dim[tid, 0]
|
|
1738
|
+
ang_axis_count = joint_axis_dim[tid, 1]
|
|
1739
|
+
|
|
1740
|
+
world_com_p = wp.transform_point(pose_p, com_p)
|
|
1741
|
+
world_com_c = wp.transform_point(pose_c, com_c)
|
|
1742
|
+
|
|
1743
|
+
# handle positional constraints
|
|
1744
|
+
if type == wp.sim.JOINT_DISTANCE:
|
|
1745
|
+
r_p = wp.transform_get_translation(X_wp) - world_com_p
|
|
1746
|
+
r_c = wp.transform_get_translation(X_wc) - world_com_c
|
|
1747
|
+
lower = joint_limit_lower[axis_start]
|
|
1748
|
+
upper = joint_limit_upper[axis_start]
|
|
1749
|
+
if lower < 0.0 and upper < 0.0:
|
|
1750
|
+
# no limits
|
|
1751
|
+
return
|
|
1752
|
+
d = wp.length(rel_p)
|
|
1753
|
+
err = 0.0
|
|
1754
|
+
if lower >= 0.0 and d < lower:
|
|
1755
|
+
err = d - lower
|
|
1756
|
+
# use a more descriptive direction vector for the constraint
|
|
1757
|
+
# in case the joint parent and child anchors are very close
|
|
1758
|
+
rel_p = err * wp.normalize(world_com_c - world_com_p)
|
|
1759
|
+
elif upper >= 0.0 and d > upper:
|
|
1760
|
+
err = d - upper
|
|
1042
1761
|
|
|
1043
1762
|
if wp.abs(err) > 1e-9:
|
|
1044
1763
|
# compute gradients
|
|
@@ -1088,7 +1807,7 @@ def solve_body_joints(
|
|
|
1088
1807
|
# compute joint target, stiffness, damping
|
|
1089
1808
|
ke_sum = float(0.0)
|
|
1090
1809
|
axis_limits = wp.spatial_vector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
1091
|
-
axis_mode = wp.
|
|
1810
|
+
axis_mode = wp.vec3i(0, 0, 0)
|
|
1092
1811
|
axis_target_ke_kd = wp.mat33(0.0)
|
|
1093
1812
|
# avoid a for loop here since local variables would need to be modified which is not yet differentiable
|
|
1094
1813
|
if lin_axis_count > 0:
|
|
@@ -1097,10 +1816,10 @@ def solve_body_joints(
|
|
|
1097
1816
|
up_temp = axis * joint_limit_upper[axis_start]
|
|
1098
1817
|
axis_limits = wp.spatial_vector(vec_min(lo_temp, up_temp), vec_max(lo_temp, up_temp))
|
|
1099
1818
|
mode = joint_axis_mode[axis_start]
|
|
1100
|
-
if mode !=
|
|
1819
|
+
if mode != JOINT_MODE_FORCE: # position or velocity target
|
|
1101
1820
|
ke = joint_target_ke[axis_start]
|
|
1102
1821
|
kd = joint_target_kd[axis_start]
|
|
1103
|
-
target =
|
|
1822
|
+
target = joint_act[axis_start]
|
|
1104
1823
|
axis_mode = update_joint_axis_mode(mode, axis, axis_mode)
|
|
1105
1824
|
axis_target_ke_kd = update_joint_axis_target_ke_kd(axis, target, ke, kd, axis_target_ke_kd)
|
|
1106
1825
|
ke_sum += ke
|
|
@@ -1111,10 +1830,10 @@ def solve_body_joints(
|
|
|
1111
1830
|
upper = joint_limit_upper[axis_idx]
|
|
1112
1831
|
axis_limits = update_joint_axis_limits(axis, lower, upper, axis_limits)
|
|
1113
1832
|
mode = joint_axis_mode[axis_idx]
|
|
1114
|
-
if mode !=
|
|
1833
|
+
if mode != JOINT_MODE_FORCE: # position or velocity target
|
|
1115
1834
|
ke = joint_target_ke[axis_idx]
|
|
1116
1835
|
kd = joint_target_kd[axis_idx]
|
|
1117
|
-
target =
|
|
1836
|
+
target = joint_act[axis_idx]
|
|
1118
1837
|
axis_mode = update_joint_axis_mode(mode, axis, axis_mode)
|
|
1119
1838
|
axis_target_ke_kd = update_joint_axis_target_ke_kd(axis, target, ke, kd, axis_target_ke_kd)
|
|
1120
1839
|
ke_sum += ke
|
|
@@ -1125,10 +1844,10 @@ def solve_body_joints(
|
|
|
1125
1844
|
upper = joint_limit_upper[axis_idx]
|
|
1126
1845
|
axis_limits = update_joint_axis_limits(axis, lower, upper, axis_limits)
|
|
1127
1846
|
mode = joint_axis_mode[axis_idx]
|
|
1128
|
-
if mode !=
|
|
1847
|
+
if mode != JOINT_MODE_FORCE: # position or velocity target
|
|
1129
1848
|
ke = joint_target_ke[axis_idx]
|
|
1130
1849
|
kd = joint_target_kd[axis_idx]
|
|
1131
|
-
target =
|
|
1850
|
+
target = joint_act[axis_idx]
|
|
1132
1851
|
axis_mode = update_joint_axis_mode(mode, axis, axis_mode)
|
|
1133
1852
|
axis_target_ke_kd = update_joint_axis_target_ke_kd(axis, target, ke, kd, axis_target_ke_kd)
|
|
1134
1853
|
ke_sum += ke
|
|
@@ -1172,12 +1891,8 @@ def solve_body_joints(
|
|
|
1172
1891
|
upper = axis_limits_upper[dim]
|
|
1173
1892
|
if e < lower:
|
|
1174
1893
|
err = e - lower
|
|
1175
|
-
compliance = linear_compliance
|
|
1176
|
-
damping = 0.0
|
|
1177
1894
|
elif e > upper:
|
|
1178
1895
|
err = e - upper
|
|
1179
|
-
compliance = linear_compliance
|
|
1180
|
-
damping = 0.0
|
|
1181
1896
|
else:
|
|
1182
1897
|
target = axis_target[dim]
|
|
1183
1898
|
if mode == JOINT_MODE_TARGET_POSITION:
|
|
@@ -1191,6 +1906,7 @@ def solve_body_joints(
|
|
|
1191
1906
|
err = (derr - target) * dt
|
|
1192
1907
|
compliance = 1.0 / axis_stiffness[dim]
|
|
1193
1908
|
damping = axis_damping[dim]
|
|
1909
|
+
derr = 0.0
|
|
1194
1910
|
|
|
1195
1911
|
if wp.abs(err) > 1e-9:
|
|
1196
1912
|
lambda_in = 0.0
|
|
@@ -1293,7 +2009,7 @@ def solve_body_joints(
|
|
|
1293
2009
|
# compute joint target, stiffness, damping
|
|
1294
2010
|
ke_sum = float(0.0)
|
|
1295
2011
|
axis_limits = wp.spatial_vector(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
|
|
1296
|
-
axis_mode = wp.
|
|
2012
|
+
axis_mode = wp.vec3i(0, 0, 0)
|
|
1297
2013
|
axis_target_ke_kd = wp.mat33(0.0)
|
|
1298
2014
|
# avoid a for loop here since local variables would need to be modified which is not yet differentiable
|
|
1299
2015
|
if ang_axis_count > 0:
|
|
@@ -1303,10 +2019,10 @@ def solve_body_joints(
|
|
|
1303
2019
|
up_temp = axis * joint_limit_upper[axis_idx]
|
|
1304
2020
|
axis_limits = wp.spatial_vector(vec_min(lo_temp, up_temp), vec_max(lo_temp, up_temp))
|
|
1305
2021
|
mode = joint_axis_mode[axis_idx]
|
|
1306
|
-
if mode !=
|
|
2022
|
+
if mode != JOINT_MODE_FORCE: # position or velocity target
|
|
1307
2023
|
ke = joint_target_ke[axis_idx]
|
|
1308
2024
|
kd = joint_target_kd[axis_idx]
|
|
1309
|
-
target =
|
|
2025
|
+
target = joint_act[axis_idx]
|
|
1310
2026
|
axis_mode = update_joint_axis_mode(mode, axis, axis_mode)
|
|
1311
2027
|
axis_target_ke_kd = update_joint_axis_target_ke_kd(axis, target, ke, kd, axis_target_ke_kd)
|
|
1312
2028
|
ke_sum += ke
|
|
@@ -1317,10 +2033,10 @@ def solve_body_joints(
|
|
|
1317
2033
|
upper = joint_limit_upper[axis_idx]
|
|
1318
2034
|
axis_limits = update_joint_axis_limits(axis, lower, upper, axis_limits)
|
|
1319
2035
|
mode = joint_axis_mode[axis_idx]
|
|
1320
|
-
if mode !=
|
|
2036
|
+
if mode != JOINT_MODE_FORCE: # position or velocity target
|
|
1321
2037
|
ke = joint_target_ke[axis_idx]
|
|
1322
2038
|
kd = joint_target_kd[axis_idx]
|
|
1323
|
-
target =
|
|
2039
|
+
target = joint_act[axis_idx]
|
|
1324
2040
|
axis_mode = update_joint_axis_mode(mode, axis, axis_mode)
|
|
1325
2041
|
axis_target_ke_kd = update_joint_axis_target_ke_kd(axis, target, ke, kd, axis_target_ke_kd)
|
|
1326
2042
|
ke_sum += ke
|
|
@@ -1331,10 +2047,10 @@ def solve_body_joints(
|
|
|
1331
2047
|
upper = joint_limit_upper[axis_idx]
|
|
1332
2048
|
axis_limits = update_joint_axis_limits(axis, lower, upper, axis_limits)
|
|
1333
2049
|
mode = joint_axis_mode[axis_idx]
|
|
1334
|
-
if mode !=
|
|
2050
|
+
if mode != JOINT_MODE_FORCE: # position or velocity target
|
|
1335
2051
|
ke = joint_target_ke[axis_idx]
|
|
1336
2052
|
kd = joint_target_kd[axis_idx]
|
|
1337
|
-
target =
|
|
2053
|
+
target = joint_act[axis_idx]
|
|
1338
2054
|
axis_mode = update_joint_axis_mode(mode, axis, axis_mode)
|
|
1339
2055
|
axis_target_ke_kd = update_joint_axis_target_ke_kd(axis, target, ke, kd, axis_target_ke_kd)
|
|
1340
2056
|
ke_sum += ke
|
|
@@ -1378,12 +2094,8 @@ def solve_body_joints(
|
|
|
1378
2094
|
upper = axis_limits_upper[dim]
|
|
1379
2095
|
if e < lower:
|
|
1380
2096
|
err = e - lower
|
|
1381
|
-
compliance = angular_compliance
|
|
1382
|
-
damping = 0.0
|
|
1383
2097
|
elif e > upper:
|
|
1384
2098
|
err = e - upper
|
|
1385
|
-
compliance = angular_compliance
|
|
1386
|
-
damping = 0.0
|
|
1387
2099
|
else:
|
|
1388
2100
|
target = axis_target[dim]
|
|
1389
2101
|
if mode == JOINT_MODE_TARGET_POSITION:
|
|
@@ -1397,6 +2109,7 @@ def solve_body_joints(
|
|
|
1397
2109
|
err = (derr - target) * dt
|
|
1398
2110
|
compliance = 1.0 / axis_stiffness[dim]
|
|
1399
2111
|
damping = axis_damping[dim]
|
|
2112
|
+
derr = 0.0
|
|
1400
2113
|
|
|
1401
2114
|
d_lambda = (
|
|
1402
2115
|
compute_angular_correction(
|
|
@@ -1404,6 +2117,7 @@ def solve_body_joints(
|
|
|
1404
2117
|
)
|
|
1405
2118
|
* angular_relaxation
|
|
1406
2119
|
)
|
|
2120
|
+
|
|
1407
2121
|
# update deltas
|
|
1408
2122
|
ang_delta_p += angular_p * d_lambda
|
|
1409
2123
|
ang_delta_c += angular_c * d_lambda
|
|
@@ -1444,11 +2158,11 @@ def compute_contact_constraint_delta(
|
|
|
1444
2158
|
denom += wp.dot(rot_angular_a, I_inv_a * rot_angular_a)
|
|
1445
2159
|
denom += wp.dot(rot_angular_b, I_inv_b * rot_angular_b)
|
|
1446
2160
|
|
|
1447
|
-
|
|
2161
|
+
delta_lambda = -err
|
|
1448
2162
|
if denom > 0.0:
|
|
1449
|
-
|
|
2163
|
+
delta_lambda /= dt * denom
|
|
1450
2164
|
|
|
1451
|
-
return
|
|
2165
|
+
return delta_lambda * relaxation
|
|
1452
2166
|
|
|
1453
2167
|
|
|
1454
2168
|
@wp.func
|
|
@@ -1487,11 +2201,11 @@ def compute_positional_correction(
|
|
|
1487
2201
|
alpha = compliance
|
|
1488
2202
|
gamma = compliance * damping
|
|
1489
2203
|
|
|
1490
|
-
|
|
2204
|
+
delta_lambda = -(err + alpha * lambda_in + gamma * derr)
|
|
1491
2205
|
if denom + alpha > 0.0:
|
|
1492
|
-
|
|
2206
|
+
delta_lambda /= (dt + gamma) * denom + alpha / dt
|
|
1493
2207
|
|
|
1494
|
-
return
|
|
2208
|
+
return delta_lambda
|
|
1495
2209
|
|
|
1496
2210
|
|
|
1497
2211
|
@wp.func
|
|
@@ -1524,11 +2238,11 @@ def compute_angular_correction(
|
|
|
1524
2238
|
alpha = compliance
|
|
1525
2239
|
gamma = compliance * damping
|
|
1526
2240
|
|
|
1527
|
-
|
|
2241
|
+
delta_lambda = -(err + alpha * lambda_in + gamma * derr)
|
|
1528
2242
|
if denom + alpha > 0.0:
|
|
1529
|
-
|
|
2243
|
+
delta_lambda /= (dt + gamma) * denom + alpha / dt
|
|
1530
2244
|
|
|
1531
|
-
return
|
|
2245
|
+
return delta_lambda
|
|
1532
2246
|
|
|
1533
2247
|
|
|
1534
2248
|
@wp.kernel
|
|
@@ -1538,9 +2252,8 @@ def solve_body_contact_positions(
|
|
|
1538
2252
|
body_com: wp.array(dtype=wp.vec3),
|
|
1539
2253
|
body_m_inv: wp.array(dtype=float),
|
|
1540
2254
|
body_I_inv: wp.array(dtype=wp.mat33),
|
|
2255
|
+
shape_body: wp.array(dtype=int),
|
|
1541
2256
|
contact_count: wp.array(dtype=int),
|
|
1542
|
-
contact_body0: wp.array(dtype=int),
|
|
1543
|
-
contact_body1: wp.array(dtype=int),
|
|
1544
2257
|
contact_point0: wp.array(dtype=wp.vec3),
|
|
1545
2258
|
contact_point1: wp.array(dtype=wp.vec3),
|
|
1546
2259
|
contact_offset0: wp.array(dtype=wp.vec3),
|
|
@@ -1556,9 +2269,6 @@ def solve_body_contact_positions(
|
|
|
1556
2269
|
contact_rolling_friction: float,
|
|
1557
2270
|
# outputs
|
|
1558
2271
|
deltas: wp.array(dtype=wp.spatial_vector),
|
|
1559
|
-
active_contact_point0: wp.array(dtype=wp.vec3),
|
|
1560
|
-
active_contact_point1: wp.array(dtype=wp.vec3),
|
|
1561
|
-
active_contact_distance: wp.array(dtype=float),
|
|
1562
2272
|
contact_inv_weight: wp.array(dtype=float),
|
|
1563
2273
|
):
|
|
1564
2274
|
tid = wp.tid()
|
|
@@ -1567,12 +2277,17 @@ def solve_body_contact_positions(
|
|
|
1567
2277
|
if tid >= count:
|
|
1568
2278
|
return
|
|
1569
2279
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
if body_a == body_b:
|
|
2280
|
+
shape_a = contact_shape0[tid]
|
|
2281
|
+
shape_b = contact_shape1[tid]
|
|
2282
|
+
if shape_a == shape_b:
|
|
1574
2283
|
return
|
|
1575
|
-
|
|
2284
|
+
body_a = -1
|
|
2285
|
+
if shape_a >= 0:
|
|
2286
|
+
body_a = shape_body[shape_a]
|
|
2287
|
+
body_b = -1
|
|
2288
|
+
if shape_b >= 0:
|
|
2289
|
+
body_b = shape_body[shape_b]
|
|
2290
|
+
if body_a == body_b:
|
|
1576
2291
|
return
|
|
1577
2292
|
|
|
1578
2293
|
# find body to world transform
|
|
@@ -1586,15 +2301,11 @@ def solve_body_contact_positions(
|
|
|
1586
2301
|
# compute body position in world space
|
|
1587
2302
|
bx_a = wp.transform_point(X_wb_a, contact_point0[tid])
|
|
1588
2303
|
bx_b = wp.transform_point(X_wb_b, contact_point1[tid])
|
|
1589
|
-
active_contact_point0[tid] = bx_a
|
|
1590
|
-
active_contact_point1[tid] = bx_b
|
|
1591
2304
|
|
|
1592
2305
|
thickness = contact_thickness[tid]
|
|
1593
2306
|
n = -contact_normal[tid]
|
|
1594
2307
|
d = wp.dot(n, bx_b - bx_a) - thickness
|
|
1595
2308
|
|
|
1596
|
-
active_contact_distance[tid] = d
|
|
1597
|
-
|
|
1598
2309
|
if d >= 0.0:
|
|
1599
2310
|
return
|
|
1600
2311
|
|
|
@@ -1632,8 +2343,6 @@ def solve_body_contact_positions(
|
|
|
1632
2343
|
# use average contact material properties
|
|
1633
2344
|
mat_nonzero = 0
|
|
1634
2345
|
mu = 0.0
|
|
1635
|
-
shape_a = contact_shape0[tid]
|
|
1636
|
-
shape_b = contact_shape1[tid]
|
|
1637
2346
|
if shape_a >= 0:
|
|
1638
2347
|
mat_nonzero += 1
|
|
1639
2348
|
mu += shape_materials.mu[shape_a]
|
|
@@ -1783,16 +2492,17 @@ def apply_rigid_restitution(
|
|
|
1783
2492
|
body_com: wp.array(dtype=wp.vec3),
|
|
1784
2493
|
body_m_inv: wp.array(dtype=float),
|
|
1785
2494
|
body_I_inv: wp.array(dtype=wp.mat33),
|
|
2495
|
+
shape_body: wp.array(dtype=int),
|
|
1786
2496
|
contact_count: wp.array(dtype=int),
|
|
1787
|
-
contact_body0: wp.array(dtype=int),
|
|
1788
|
-
contact_body1: wp.array(dtype=int),
|
|
1789
2497
|
contact_normal: wp.array(dtype=wp.vec3),
|
|
1790
2498
|
contact_shape0: wp.array(dtype=int),
|
|
1791
2499
|
contact_shape1: wp.array(dtype=int),
|
|
1792
2500
|
shape_materials: ModelShapeMaterials,
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
2501
|
+
contact_point0: wp.array(dtype=wp.vec3),
|
|
2502
|
+
contact_point1: wp.array(dtype=wp.vec3),
|
|
2503
|
+
contact_offset0: wp.array(dtype=wp.vec3),
|
|
2504
|
+
contact_offset1: wp.array(dtype=wp.vec3),
|
|
2505
|
+
contact_thickness: wp.array(dtype=float),
|
|
1796
2506
|
contact_inv_weight: wp.array(dtype=float),
|
|
1797
2507
|
gravity: wp.vec3,
|
|
1798
2508
|
dt: float,
|
|
@@ -1804,26 +2514,28 @@ def apply_rigid_restitution(
|
|
|
1804
2514
|
count = contact_count[0]
|
|
1805
2515
|
if tid >= count:
|
|
1806
2516
|
return
|
|
1807
|
-
|
|
1808
|
-
|
|
2517
|
+
shape_a = contact_shape0[tid]
|
|
2518
|
+
shape_b = contact_shape1[tid]
|
|
2519
|
+
if shape_a == shape_b:
|
|
1809
2520
|
return
|
|
2521
|
+
body_a = -1
|
|
2522
|
+
body_b = -1
|
|
1810
2523
|
|
|
1811
2524
|
# use average contact material properties
|
|
1812
2525
|
mat_nonzero = 0
|
|
1813
2526
|
restitution = 0.0
|
|
1814
|
-
shape_a = contact_shape0[tid]
|
|
1815
|
-
shape_b = contact_shape1[tid]
|
|
1816
2527
|
if shape_a >= 0:
|
|
1817
2528
|
mat_nonzero += 1
|
|
1818
2529
|
restitution += shape_materials.restitution[shape_a]
|
|
2530
|
+
body_a = shape_body[shape_a]
|
|
1819
2531
|
if shape_b >= 0:
|
|
1820
2532
|
mat_nonzero += 1
|
|
1821
2533
|
restitution += shape_materials.restitution[shape_b]
|
|
2534
|
+
body_b = shape_body[shape_b]
|
|
1822
2535
|
if mat_nonzero > 0:
|
|
1823
2536
|
restitution /= float(mat_nonzero)
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
body_b = contact_body1[tid]
|
|
2537
|
+
if body_a == body_b:
|
|
2538
|
+
return
|
|
1827
2539
|
|
|
1828
2540
|
m_inv_a = 0.0
|
|
1829
2541
|
m_inv_b = 0.0
|
|
@@ -1858,37 +2570,43 @@ def apply_rigid_restitution(
|
|
|
1858
2570
|
I_inv_b = body_I_inv[body_b]
|
|
1859
2571
|
com_b = body_com[body_b]
|
|
1860
2572
|
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
r_a = bx_a - wp.transform_point(X_wb_a, com_a)
|
|
1865
|
-
r_b = bx_b - wp.transform_point(X_wb_b, com_b)
|
|
2573
|
+
# compute body position in world space
|
|
2574
|
+
bx_a = wp.transform_point(X_wb_a_prev, contact_point0[tid] + contact_offset0[tid])
|
|
2575
|
+
bx_b = wp.transform_point(X_wb_b_prev, contact_point1[tid] + contact_offset1[tid])
|
|
1866
2576
|
|
|
2577
|
+
thickness = contact_thickness[tid]
|
|
1867
2578
|
n = contact_normal[tid]
|
|
2579
|
+
d = -wp.dot(n, bx_b - bx_a) - thickness
|
|
2580
|
+
if d >= 0.0:
|
|
2581
|
+
return
|
|
2582
|
+
|
|
2583
|
+
r_a = bx_a - wp.transform_point(X_wb_a_prev, com_a)
|
|
2584
|
+
r_b = bx_b - wp.transform_point(X_wb_b_prev, com_b)
|
|
2585
|
+
|
|
2586
|
+
rxn_a = wp.vec3(0.0)
|
|
2587
|
+
rxn_b = wp.vec3(0.0)
|
|
1868
2588
|
if body_a >= 0:
|
|
1869
2589
|
v_a = velocity_at_point(body_qd_prev[body_a], r_a) + gravity * dt
|
|
1870
2590
|
v_a_new = velocity_at_point(body_qd[body_a], r_a)
|
|
1871
2591
|
q_a = wp.transform_get_rotation(X_wb_a_prev)
|
|
1872
|
-
|
|
2592
|
+
rxn_a = wp.quat_rotate_inv(q_a, wp.cross(r_a, n))
|
|
1873
2593
|
# Eq. 2
|
|
1874
|
-
inv_mass_a = m_inv_a + wp.dot(
|
|
1875
|
-
# if
|
|
1876
|
-
#
|
|
1877
|
-
#
|
|
2594
|
+
inv_mass_a = m_inv_a + wp.dot(rxn_a, I_inv_a * rxn_a)
|
|
2595
|
+
# if contact_inv_weight:
|
|
2596
|
+
# if contact_inv_weight[body_a] > 0.0:
|
|
2597
|
+
# inv_mass_a *= contact_inv_weight[body_a]
|
|
1878
2598
|
inv_mass += inv_mass_a
|
|
1879
|
-
# inv_mass += m_inv_a + wp.dot(rxn, I_inv_a * rxn)
|
|
1880
2599
|
if body_b >= 0:
|
|
1881
2600
|
v_b = velocity_at_point(body_qd_prev[body_b], r_b) + gravity * dt
|
|
1882
2601
|
v_b_new = velocity_at_point(body_qd[body_b], r_b)
|
|
1883
2602
|
q_b = wp.transform_get_rotation(X_wb_b_prev)
|
|
1884
|
-
|
|
2603
|
+
rxn_b = wp.quat_rotate_inv(q_b, wp.cross(r_b, n))
|
|
1885
2604
|
# Eq. 3
|
|
1886
|
-
inv_mass_b = m_inv_b + wp.dot(
|
|
1887
|
-
# if
|
|
1888
|
-
#
|
|
1889
|
-
#
|
|
2605
|
+
inv_mass_b = m_inv_b + wp.dot(rxn_b, I_inv_b * rxn_b)
|
|
2606
|
+
# if contact_inv_weight:
|
|
2607
|
+
# if contact_inv_weight[body_b] > 0.0:
|
|
2608
|
+
# inv_mass_b *= contact_inv_weight[body_b]
|
|
1890
2609
|
inv_mass += inv_mass_b
|
|
1891
|
-
# inv_mass += m_inv_b + wp.dot(rxn, I_inv_b * rxn)
|
|
1892
2610
|
|
|
1893
2611
|
if inv_mass == 0.0:
|
|
1894
2612
|
return
|
|
@@ -1897,36 +2615,40 @@ def apply_rigid_restitution(
|
|
|
1897
2615
|
rel_vel_old = wp.dot(n, v_a - v_b)
|
|
1898
2616
|
rel_vel_new = wp.dot(n, v_a_new - v_b_new)
|
|
1899
2617
|
|
|
1900
|
-
|
|
1901
|
-
|
|
2618
|
+
if rel_vel_old >= 0.0:
|
|
2619
|
+
return
|
|
2620
|
+
|
|
2621
|
+
# Eq. 34
|
|
2622
|
+
dv = (-rel_vel_new - restitution * rel_vel_old) / inv_mass
|
|
1902
2623
|
|
|
1903
2624
|
# Eq. 33
|
|
1904
|
-
p = dv / inv_mass
|
|
1905
2625
|
if body_a >= 0:
|
|
1906
|
-
|
|
1907
|
-
if contact_inv_weight:
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
q_a = wp.transform_get_rotation(
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
wp.atomic_add(deltas, body_a, wp.spatial_vector(dq, p_a * m_inv_a))
|
|
2626
|
+
dv_a = dv
|
|
2627
|
+
# if contact_inv_weight:
|
|
2628
|
+
# if contact_inv_weight[body_a] > 0.0:
|
|
2629
|
+
# dv_a *= contact_inv_weight[body_a]
|
|
2630
|
+
q_a = wp.transform_get_rotation(X_wb_a_prev)
|
|
2631
|
+
dq = wp.quat_rotate(q_a, I_inv_a * rxn_a * dv_a)
|
|
2632
|
+
wp.atomic_add(deltas, body_a, wp.spatial_vector(dq, n * m_inv_a * dv_a))
|
|
1914
2633
|
|
|
1915
2634
|
if body_b >= 0:
|
|
1916
|
-
|
|
1917
|
-
if contact_inv_weight:
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
q_b = wp.transform_get_rotation(
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2635
|
+
dv_b = -dv
|
|
2636
|
+
# if contact_inv_weight:
|
|
2637
|
+
# if contact_inv_weight[body_b] > 0.0:
|
|
2638
|
+
# dv_b *= contact_inv_weight[body_b]
|
|
2639
|
+
q_b = wp.transform_get_rotation(X_wb_b_prev)
|
|
2640
|
+
dq = wp.quat_rotate(q_b, I_inv_b * rxn_b * dv_b)
|
|
2641
|
+
wp.atomic_add(deltas, body_b, wp.spatial_vector(dq, n * m_inv_b * dv_b))
|
|
2642
|
+
|
|
1924
2643
|
|
|
2644
|
+
class XPBDIntegrator(Integrator):
|
|
2645
|
+
"""An implicit integrator using eXtended Position-Based Dynamics (XPBD) for rigid and soft body simulation.
|
|
1925
2646
|
|
|
1926
|
-
|
|
1927
|
-
|
|
2647
|
+
References:
|
|
2648
|
+
- Miles Macklin, Matthias Müller, and Nuttapong Chentanez. 2016. XPBD: position-based simulation of compliant constrained dynamics. In Proceedings of the 9th International Conference on Motion in Games (MIG '16). Association for Computing Machinery, New York, NY, USA, 49-54. https://doi.org/10.1145/2994258.2994272
|
|
2649
|
+
- Matthias Müller, Miles Macklin, Nuttapong Chentanez, Stefan Jeschke, and Tae-Yong Kim. 2020. Detailed rigid body simulation with extended position based dynamics. In Proceedings of the ACM SIGGRAPH/Eurographics Symposium on Computer Animation (SCA '20). Eurographics Association, Goslar, DEU, Article 10, 1-12. https://doi.org/10.1111/cgf.14105
|
|
1928
2650
|
|
|
1929
|
-
After constructing
|
|
2651
|
+
After constructing :class:`Model`, :class:`State`, and :class:`Control` (optional) objects, this time-integrator
|
|
1930
2652
|
may be used to advance the simulation state forward in time.
|
|
1931
2653
|
|
|
1932
2654
|
Example
|
|
@@ -1934,11 +2656,11 @@ class XPBDIntegrator:
|
|
|
1934
2656
|
|
|
1935
2657
|
.. code-block:: python
|
|
1936
2658
|
|
|
1937
|
-
integrator = wp.
|
|
2659
|
+
integrator = wp.XPBDIntegrator()
|
|
1938
2660
|
|
|
1939
2661
|
# simulation loop
|
|
1940
2662
|
for i in range(100):
|
|
1941
|
-
state = integrator.simulate(model, state_in, state_out, dt)
|
|
2663
|
+
state = integrator.simulate(model, state_in, state_out, dt, control)
|
|
1942
2664
|
|
|
1943
2665
|
"""
|
|
1944
2666
|
|
|
@@ -1969,36 +2691,164 @@ class XPBDIntegrator:
|
|
|
1969
2691
|
|
|
1970
2692
|
self.enable_restitution = enable_restitution
|
|
1971
2693
|
|
|
1972
|
-
|
|
2694
|
+
self.compute_body_velocity_from_position_delta = False
|
|
2695
|
+
|
|
2696
|
+
# helper variables to track constraint resolution vars
|
|
2697
|
+
self._particle_delta_counter = 0
|
|
2698
|
+
self._body_delta_counter = 0
|
|
2699
|
+
|
|
2700
|
+
def apply_particle_deltas(
|
|
2701
|
+
self,
|
|
2702
|
+
model: Model,
|
|
2703
|
+
state_in: State,
|
|
2704
|
+
state_out: State,
|
|
2705
|
+
particle_deltas: wp.array,
|
|
2706
|
+
dt: float,
|
|
2707
|
+
):
|
|
2708
|
+
if state_in.requires_grad:
|
|
2709
|
+
particle_q = state_out.particle_q
|
|
2710
|
+
# allocate new particle arrays so gradients can be tracked correctly without overwriting
|
|
2711
|
+
new_particle_q = wp.empty_like(state_out.particle_q)
|
|
2712
|
+
new_particle_qd = wp.empty_like(state_out.particle_qd)
|
|
2713
|
+
self._particle_delta_counter += 1
|
|
2714
|
+
else:
|
|
2715
|
+
if self._particle_delta_counter == 0:
|
|
2716
|
+
particle_q = state_out.particle_q
|
|
2717
|
+
new_particle_q = state_in.particle_q
|
|
2718
|
+
new_particle_qd = state_in.particle_qd
|
|
2719
|
+
else:
|
|
2720
|
+
particle_q = state_in.particle_q
|
|
2721
|
+
new_particle_q = state_out.particle_q
|
|
2722
|
+
new_particle_qd = state_out.particle_qd
|
|
2723
|
+
self._particle_delta_counter = 1 - self._particle_delta_counter
|
|
2724
|
+
|
|
2725
|
+
wp.launch(
|
|
2726
|
+
kernel=apply_particle_deltas,
|
|
2727
|
+
dim=model.particle_count,
|
|
2728
|
+
inputs=[
|
|
2729
|
+
self.particle_q_init,
|
|
2730
|
+
particle_q,
|
|
2731
|
+
model.particle_flags,
|
|
2732
|
+
particle_deltas,
|
|
2733
|
+
dt,
|
|
2734
|
+
model.particle_max_velocity,
|
|
2735
|
+
],
|
|
2736
|
+
outputs=[new_particle_q, new_particle_qd],
|
|
2737
|
+
device=model.device,
|
|
2738
|
+
)
|
|
2739
|
+
|
|
2740
|
+
if state_in.requires_grad:
|
|
2741
|
+
state_out.particle_q = new_particle_q
|
|
2742
|
+
state_out.particle_qd = new_particle_qd
|
|
2743
|
+
|
|
2744
|
+
return new_particle_q, new_particle_qd
|
|
2745
|
+
|
|
2746
|
+
def apply_body_deltas(
|
|
2747
|
+
self,
|
|
2748
|
+
model: Model,
|
|
2749
|
+
state_in: State,
|
|
2750
|
+
state_out: State,
|
|
2751
|
+
body_deltas: wp.array,
|
|
2752
|
+
dt: float,
|
|
2753
|
+
rigid_contact_inv_weight: wp.array = None,
|
|
2754
|
+
):
|
|
2755
|
+
with wp.ScopedTimer("apply_body_deltas", False):
|
|
2756
|
+
if state_in.requires_grad:
|
|
2757
|
+
body_q = state_out.body_q
|
|
2758
|
+
body_qd = state_out.body_qd
|
|
2759
|
+
new_body_q = wp.clone(body_q)
|
|
2760
|
+
new_body_qd = wp.clone(body_qd)
|
|
2761
|
+
self._body_delta_counter += 1
|
|
2762
|
+
else:
|
|
2763
|
+
if self._body_delta_counter == 0:
|
|
2764
|
+
body_q = state_out.body_q
|
|
2765
|
+
body_qd = state_out.body_qd
|
|
2766
|
+
new_body_q = state_in.body_q
|
|
2767
|
+
new_body_qd = state_in.body_qd
|
|
2768
|
+
else:
|
|
2769
|
+
body_q = state_in.body_q
|
|
2770
|
+
body_qd = state_in.body_qd
|
|
2771
|
+
new_body_q = state_out.body_q
|
|
2772
|
+
new_body_qd = state_out.body_qd
|
|
2773
|
+
self._body_delta_counter = 1 - self._body_delta_counter
|
|
2774
|
+
|
|
2775
|
+
wp.launch(
|
|
2776
|
+
kernel=apply_body_deltas,
|
|
2777
|
+
dim=model.body_count,
|
|
2778
|
+
inputs=[
|
|
2779
|
+
body_q,
|
|
2780
|
+
body_qd,
|
|
2781
|
+
model.body_com,
|
|
2782
|
+
model.body_inertia,
|
|
2783
|
+
model.body_inv_mass,
|
|
2784
|
+
model.body_inv_inertia,
|
|
2785
|
+
body_deltas,
|
|
2786
|
+
rigid_contact_inv_weight,
|
|
2787
|
+
dt,
|
|
2788
|
+
],
|
|
2789
|
+
outputs=[
|
|
2790
|
+
new_body_q,
|
|
2791
|
+
new_body_qd,
|
|
2792
|
+
],
|
|
2793
|
+
device=model.device,
|
|
2794
|
+
)
|
|
2795
|
+
|
|
2796
|
+
if state_in.requires_grad:
|
|
2797
|
+
state_out.body_q = new_body_q
|
|
2798
|
+
state_out.body_qd = new_body_qd
|
|
2799
|
+
|
|
2800
|
+
return new_body_q, new_body_qd
|
|
2801
|
+
|
|
2802
|
+
def simulate(self, model: Model, state_in: State, state_out: State, dt: float, control: Control = None):
|
|
2803
|
+
requires_grad = state_in.requires_grad
|
|
2804
|
+
self._particle_delta_counter = 0
|
|
2805
|
+
self._body_delta_counter = 0
|
|
2806
|
+
|
|
2807
|
+
particle_q = None
|
|
2808
|
+
particle_qd = None
|
|
2809
|
+
particle_deltas = None
|
|
2810
|
+
|
|
2811
|
+
body_q = None
|
|
2812
|
+
body_qd = None
|
|
2813
|
+
body_deltas = None
|
|
2814
|
+
|
|
2815
|
+
rigid_contact_inv_weight = None
|
|
2816
|
+
|
|
2817
|
+
if model.rigid_contact_max > 0:
|
|
2818
|
+
if self.rigid_contact_con_weighting:
|
|
2819
|
+
rigid_contact_inv_weight = wp.zeros_like(model.rigid_contact_thickness)
|
|
2820
|
+
rigid_contact_inv_weight_init = None
|
|
2821
|
+
|
|
2822
|
+
if control is None:
|
|
2823
|
+
control = model.control(clone_variables=False)
|
|
2824
|
+
|
|
1973
2825
|
with wp.ScopedTimer("simulate", False):
|
|
1974
|
-
particle_q = None
|
|
1975
|
-
particle_qd = None
|
|
1976
2826
|
|
|
1977
2827
|
if model.particle_count:
|
|
1978
2828
|
if requires_grad:
|
|
1979
|
-
particle_q =
|
|
1980
|
-
particle_qd =
|
|
2829
|
+
particle_q = state_out.particle_q
|
|
2830
|
+
particle_qd = state_out.particle_qd
|
|
1981
2831
|
else:
|
|
1982
2832
|
particle_q = state_out.particle_q
|
|
1983
2833
|
particle_qd = state_out.particle_qd
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
model.particle_inv_mass,
|
|
1992
|
-
model.particle_flags,
|
|
1993
|
-
model.gravity,
|
|
1994
|
-
dt,
|
|
1995
|
-
model.particle_max_velocity,
|
|
1996
|
-
],
|
|
1997
|
-
outputs=[particle_q, particle_qd],
|
|
1998
|
-
device=model.device,
|
|
1999
|
-
)
|
|
2834
|
+
|
|
2835
|
+
self.particle_q_init = wp.clone(state_in.particle_q)
|
|
2836
|
+
if self.enable_restitution:
|
|
2837
|
+
self.particle_qd_init = wp.clone(state_in.particle_qd)
|
|
2838
|
+
particle_deltas = wp.empty_like(state_out.particle_qd)
|
|
2839
|
+
|
|
2840
|
+
self.integrate_particles(model, state_in, state_out, dt)
|
|
2000
2841
|
|
|
2001
2842
|
if model.body_count:
|
|
2843
|
+
body_q = state_out.body_q
|
|
2844
|
+
body_qd = state_out.body_qd
|
|
2845
|
+
|
|
2846
|
+
if self.compute_body_velocity_from_position_delta or self.enable_restitution:
|
|
2847
|
+
body_q_init = wp.clone(state_in.body_q)
|
|
2848
|
+
body_qd_init = wp.clone(state_in.body_qd)
|
|
2849
|
+
|
|
2850
|
+
body_deltas = wp.empty_like(state_out.body_qd)
|
|
2851
|
+
|
|
2002
2852
|
if model.joint_count:
|
|
2003
2853
|
wp.launch(
|
|
2004
2854
|
kernel=apply_joint_torques,
|
|
@@ -2016,416 +2866,332 @@ class XPBDIntegrator:
|
|
|
2016
2866
|
model.joint_axis_start,
|
|
2017
2867
|
model.joint_axis_dim,
|
|
2018
2868
|
model.joint_axis,
|
|
2019
|
-
model.
|
|
2869
|
+
model.joint_axis_mode,
|
|
2870
|
+
control.joint_act,
|
|
2020
2871
|
],
|
|
2021
2872
|
outputs=[state_in.body_f],
|
|
2022
2873
|
device=model.device,
|
|
2023
2874
|
)
|
|
2024
2875
|
|
|
2025
|
-
|
|
2026
|
-
kernel=integrate_bodies,
|
|
2027
|
-
dim=model.body_count,
|
|
2028
|
-
inputs=[
|
|
2029
|
-
state_in.body_q,
|
|
2030
|
-
state_in.body_qd,
|
|
2031
|
-
state_in.body_f,
|
|
2032
|
-
model.body_com,
|
|
2033
|
-
model.body_mass,
|
|
2034
|
-
model.body_inertia,
|
|
2035
|
-
model.body_inv_mass,
|
|
2036
|
-
model.body_inv_inertia,
|
|
2037
|
-
model.gravity,
|
|
2038
|
-
self.angular_damping,
|
|
2039
|
-
dt,
|
|
2040
|
-
],
|
|
2041
|
-
outputs=[state_out.body_q, state_out.body_qd],
|
|
2042
|
-
device=model.device,
|
|
2043
|
-
)
|
|
2876
|
+
self.integrate_bodies(model, state_in, state_out, dt, self.angular_damping)
|
|
2044
2877
|
|
|
2878
|
+
spring_constraint_lambdas = None
|
|
2045
2879
|
if model.spring_count:
|
|
2046
|
-
|
|
2047
|
-
|
|
2880
|
+
spring_constraint_lambdas = wp.empty_like(model.spring_rest_length)
|
|
2881
|
+
edge_constraint_lambdas = None
|
|
2048
2882
|
if model.edge_count:
|
|
2049
|
-
|
|
2883
|
+
edge_constraint_lambdas = wp.empty_like(model.edge_rest_angle)
|
|
2050
2884
|
|
|
2051
2885
|
for i in range(self.iterations):
|
|
2052
|
-
# print(f"### iteration {i} / {self.iterations-1}")
|
|
2053
2886
|
|
|
2054
|
-
|
|
2055
|
-
if requires_grad:
|
|
2056
|
-
out_body_q = wp.clone(state_out.body_q)
|
|
2057
|
-
out_body_qd = wp.clone(state_out.body_qd)
|
|
2058
|
-
state_out.body_deltas = wp.zeros_like(state_out.body_deltas)
|
|
2059
|
-
else:
|
|
2060
|
-
out_body_q = state_out.body_q
|
|
2061
|
-
out_body_qd = state_out.body_qd
|
|
2062
|
-
state_out.body_deltas.zero_()
|
|
2063
|
-
else:
|
|
2064
|
-
out_body_q = None
|
|
2065
|
-
out_body_qd = None
|
|
2887
|
+
with wp.ScopedTimer(f"iteration_{i}", False):
|
|
2066
2888
|
|
|
2067
|
-
|
|
2068
|
-
# handle particles
|
|
2069
|
-
if model.particle_count:
|
|
2070
|
-
if requires_grad:
|
|
2071
|
-
deltas = wp.zeros_like(state_out.particle_f)
|
|
2072
|
-
else:
|
|
2073
|
-
deltas = state_out.particle_f
|
|
2074
|
-
deltas.zero_()
|
|
2889
|
+
if model.body_count:
|
|
2075
2890
|
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2891
|
+
if requires_grad and i > 0:
|
|
2892
|
+
body_deltas = wp.zeros_like(body_deltas)
|
|
2893
|
+
else:
|
|
2894
|
+
body_deltas.zero_()
|
|
2895
|
+
|
|
2896
|
+
if model.particle_count:
|
|
2897
|
+
|
|
2898
|
+
if requires_grad and i > 0:
|
|
2899
|
+
particle_deltas = wp.zeros_like(particle_deltas)
|
|
2900
|
+
else:
|
|
2901
|
+
particle_deltas.zero_()
|
|
2902
|
+
|
|
2903
|
+
# particle ground contact
|
|
2904
|
+
if model.ground:
|
|
2905
|
+
wp.launch(
|
|
2906
|
+
kernel=solve_particle_ground_contacts,
|
|
2907
|
+
dim=model.particle_count,
|
|
2908
|
+
inputs=[
|
|
2909
|
+
particle_q,
|
|
2910
|
+
particle_qd,
|
|
2911
|
+
model.particle_inv_mass,
|
|
2912
|
+
model.particle_radius,
|
|
2913
|
+
model.particle_flags,
|
|
2914
|
+
model.soft_contact_ke,
|
|
2915
|
+
model.soft_contact_kd,
|
|
2916
|
+
model.soft_contact_kf,
|
|
2917
|
+
model.soft_contact_mu,
|
|
2918
|
+
model.ground_plane,
|
|
2919
|
+
dt,
|
|
2920
|
+
self.soft_contact_relaxation,
|
|
2921
|
+
],
|
|
2922
|
+
outputs=[particle_deltas],
|
|
2923
|
+
device=model.device,
|
|
2924
|
+
)
|
|
2925
|
+
|
|
2926
|
+
# particle-rigid body contacts (besides ground plane)
|
|
2927
|
+
if model.shape_count > 1:
|
|
2928
|
+
wp.launch(
|
|
2929
|
+
kernel=solve_particle_shape_contacts,
|
|
2930
|
+
dim=model.soft_contact_max,
|
|
2931
|
+
inputs=[
|
|
2932
|
+
particle_q,
|
|
2933
|
+
particle_qd,
|
|
2934
|
+
model.particle_inv_mass,
|
|
2935
|
+
model.particle_radius,
|
|
2936
|
+
model.particle_flags,
|
|
2937
|
+
body_q,
|
|
2938
|
+
body_qd,
|
|
2939
|
+
model.body_com,
|
|
2940
|
+
model.body_inv_mass,
|
|
2941
|
+
model.body_inv_inertia,
|
|
2942
|
+
model.shape_body,
|
|
2943
|
+
model.shape_materials,
|
|
2944
|
+
model.soft_contact_mu,
|
|
2945
|
+
model.particle_adhesion,
|
|
2946
|
+
model.soft_contact_count,
|
|
2947
|
+
model.soft_contact_particle,
|
|
2948
|
+
model.soft_contact_shape,
|
|
2949
|
+
model.soft_contact_body_pos,
|
|
2950
|
+
model.soft_contact_body_vel,
|
|
2951
|
+
model.soft_contact_normal,
|
|
2952
|
+
model.soft_contact_max,
|
|
2953
|
+
dt,
|
|
2954
|
+
self.soft_contact_relaxation,
|
|
2955
|
+
],
|
|
2956
|
+
# outputs
|
|
2957
|
+
outputs=[particle_deltas, body_deltas],
|
|
2958
|
+
device=model.device,
|
|
2959
|
+
)
|
|
2960
|
+
|
|
2961
|
+
if model.particle_max_radius > 0.0 and model.particle_count > 1:
|
|
2962
|
+
# assert model.particle_grid.reserved, "model.particle_grid must be built, see HashGrid.build()"
|
|
2963
|
+
wp.launch(
|
|
2964
|
+
kernel=solve_particle_particle_contacts,
|
|
2965
|
+
dim=model.particle_count,
|
|
2966
|
+
inputs=[
|
|
2967
|
+
model.particle_grid.id,
|
|
2968
|
+
particle_q,
|
|
2969
|
+
particle_qd,
|
|
2970
|
+
model.particle_inv_mass,
|
|
2971
|
+
model.particle_radius,
|
|
2972
|
+
model.particle_flags,
|
|
2973
|
+
model.particle_mu,
|
|
2974
|
+
model.particle_cohesion,
|
|
2975
|
+
model.particle_max_radius,
|
|
2976
|
+
dt,
|
|
2977
|
+
self.soft_contact_relaxation,
|
|
2978
|
+
],
|
|
2979
|
+
outputs=[particle_deltas],
|
|
2980
|
+
device=model.device,
|
|
2981
|
+
)
|
|
2982
|
+
|
|
2983
|
+
# distance constraints
|
|
2984
|
+
if model.spring_count:
|
|
2985
|
+
spring_constraint_lambdas.zero_()
|
|
2986
|
+
wp.launch(
|
|
2987
|
+
kernel=solve_springs,
|
|
2988
|
+
dim=model.spring_count,
|
|
2989
|
+
inputs=[
|
|
2990
|
+
particle_q,
|
|
2991
|
+
particle_qd,
|
|
2992
|
+
model.particle_inv_mass,
|
|
2993
|
+
model.spring_indices,
|
|
2994
|
+
model.spring_rest_length,
|
|
2995
|
+
model.spring_stiffness,
|
|
2996
|
+
model.spring_damping,
|
|
2997
|
+
dt,
|
|
2998
|
+
spring_constraint_lambdas,
|
|
2999
|
+
],
|
|
3000
|
+
outputs=[particle_deltas],
|
|
3001
|
+
device=model.device,
|
|
3002
|
+
)
|
|
3003
|
+
|
|
3004
|
+
# bending constraints
|
|
3005
|
+
if model.edge_count:
|
|
3006
|
+
edge_constraint_lambdas.zero_()
|
|
3007
|
+
wp.launch(
|
|
3008
|
+
kernel=bending_constraint,
|
|
3009
|
+
dim=model.edge_count,
|
|
3010
|
+
inputs=[
|
|
3011
|
+
particle_q,
|
|
3012
|
+
particle_qd,
|
|
3013
|
+
model.particle_inv_mass,
|
|
3014
|
+
model.edge_indices,
|
|
3015
|
+
model.edge_rest_angle,
|
|
3016
|
+
model.edge_bending_properties,
|
|
3017
|
+
dt,
|
|
3018
|
+
edge_constraint_lambdas,
|
|
3019
|
+
],
|
|
3020
|
+
outputs=[particle_deltas],
|
|
3021
|
+
device=model.device,
|
|
3022
|
+
)
|
|
3023
|
+
|
|
3024
|
+
# tetrahedral FEM
|
|
3025
|
+
if model.tet_count:
|
|
3026
|
+
wp.launch(
|
|
3027
|
+
kernel=solve_tetrahedra,
|
|
3028
|
+
dim=model.tet_count,
|
|
3029
|
+
inputs=[
|
|
3030
|
+
particle_q,
|
|
3031
|
+
particle_qd,
|
|
3032
|
+
model.particle_inv_mass,
|
|
3033
|
+
model.tet_indices,
|
|
3034
|
+
model.tet_poses,
|
|
3035
|
+
model.tet_activations,
|
|
3036
|
+
model.tet_materials,
|
|
3037
|
+
dt,
|
|
3038
|
+
self.soft_body_relaxation,
|
|
3039
|
+
],
|
|
3040
|
+
outputs=[particle_deltas],
|
|
3041
|
+
device=model.device,
|
|
3042
|
+
)
|
|
3043
|
+
|
|
3044
|
+
particle_q, particle_qd = self.apply_particle_deltas(
|
|
3045
|
+
model, state_in, state_out, particle_deltas, dt
|
|
2097
3046
|
)
|
|
2098
3047
|
|
|
2099
|
-
#
|
|
2100
|
-
|
|
3048
|
+
# handle rigid bodies
|
|
3049
|
+
# ----------------------------
|
|
3050
|
+
|
|
3051
|
+
if model.joint_count:
|
|
3052
|
+
|
|
3053
|
+
# wp.launch(
|
|
3054
|
+
# kernel=solve_simple_body_joints,
|
|
3055
|
+
# dim=model.joint_count,
|
|
3056
|
+
# inputs=[
|
|
3057
|
+
# body_q,
|
|
3058
|
+
# body_qd,
|
|
3059
|
+
# model.body_com,
|
|
3060
|
+
# model.body_inv_mass,
|
|
3061
|
+
# model.body_inv_inertia,
|
|
3062
|
+
# model.joint_type,
|
|
3063
|
+
# model.joint_enabled,
|
|
3064
|
+
# model.joint_parent,
|
|
3065
|
+
# model.joint_child,
|
|
3066
|
+
# model.joint_X_p,
|
|
3067
|
+
# model.joint_X_c,
|
|
3068
|
+
# model.joint_limit_lower,
|
|
3069
|
+
# model.joint_limit_upper,
|
|
3070
|
+
# model.joint_axis_start,
|
|
3071
|
+
# model.joint_axis_dim,
|
|
3072
|
+
# model.joint_axis_mode,
|
|
3073
|
+
# model.joint_axis,
|
|
3074
|
+
# control.joint_target,
|
|
3075
|
+
# model.joint_target_ke,
|
|
3076
|
+
# model.joint_target_kd,
|
|
3077
|
+
# model.joint_linear_compliance,
|
|
3078
|
+
# model.joint_angular_compliance,
|
|
3079
|
+
# self.joint_angular_relaxation,
|
|
3080
|
+
# self.joint_linear_relaxation,
|
|
3081
|
+
# dt,
|
|
3082
|
+
# ],
|
|
3083
|
+
# outputs=[body_deltas],
|
|
3084
|
+
# device=model.device,
|
|
3085
|
+
# )
|
|
3086
|
+
|
|
2101
3087
|
wp.launch(
|
|
2102
|
-
kernel=
|
|
2103
|
-
dim=model.
|
|
3088
|
+
kernel=solve_body_joints,
|
|
3089
|
+
dim=model.joint_count,
|
|
2104
3090
|
inputs=[
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
model.particle_inv_mass,
|
|
2108
|
-
model.particle_radius,
|
|
2109
|
-
model.particle_flags,
|
|
2110
|
-
out_body_q,
|
|
2111
|
-
out_body_qd,
|
|
3091
|
+
body_q,
|
|
3092
|
+
body_qd,
|
|
2112
3093
|
model.body_com,
|
|
2113
3094
|
model.body_inv_mass,
|
|
2114
3095
|
model.body_inv_inertia,
|
|
2115
|
-
model.
|
|
2116
|
-
model.
|
|
2117
|
-
model.
|
|
2118
|
-
model.
|
|
2119
|
-
model.
|
|
2120
|
-
model.
|
|
2121
|
-
model.
|
|
2122
|
-
model.
|
|
2123
|
-
model.
|
|
2124
|
-
model.
|
|
2125
|
-
model.
|
|
3096
|
+
model.joint_type,
|
|
3097
|
+
model.joint_enabled,
|
|
3098
|
+
model.joint_parent,
|
|
3099
|
+
model.joint_child,
|
|
3100
|
+
model.joint_X_p,
|
|
3101
|
+
model.joint_X_c,
|
|
3102
|
+
model.joint_limit_lower,
|
|
3103
|
+
model.joint_limit_upper,
|
|
3104
|
+
model.joint_axis_start,
|
|
3105
|
+
model.joint_axis_dim,
|
|
3106
|
+
model.joint_axis_mode,
|
|
3107
|
+
model.joint_axis,
|
|
3108
|
+
control.joint_act,
|
|
3109
|
+
model.joint_target_ke,
|
|
3110
|
+
model.joint_target_kd,
|
|
3111
|
+
model.joint_linear_compliance,
|
|
3112
|
+
model.joint_angular_compliance,
|
|
3113
|
+
self.joint_angular_relaxation,
|
|
3114
|
+
self.joint_linear_relaxation,
|
|
2126
3115
|
dt,
|
|
2127
|
-
self.soft_contact_relaxation,
|
|
2128
3116
|
],
|
|
2129
|
-
|
|
2130
|
-
outputs=[deltas, state_out.body_deltas],
|
|
3117
|
+
outputs=[body_deltas],
|
|
2131
3118
|
device=model.device,
|
|
2132
3119
|
)
|
|
2133
3120
|
|
|
2134
|
-
|
|
2135
|
-
wp.launch(
|
|
2136
|
-
kernel=solve_particle_particle_contacts,
|
|
2137
|
-
dim=model.particle_count,
|
|
2138
|
-
inputs=[
|
|
2139
|
-
model.particle_grid.id,
|
|
2140
|
-
particle_q,
|
|
2141
|
-
particle_qd,
|
|
2142
|
-
model.particle_inv_mass,
|
|
2143
|
-
model.particle_radius,
|
|
2144
|
-
model.particle_flags,
|
|
2145
|
-
model.particle_mu,
|
|
2146
|
-
model.particle_cohesion,
|
|
2147
|
-
model.particle_max_radius,
|
|
2148
|
-
dt,
|
|
2149
|
-
self.soft_contact_relaxation,
|
|
2150
|
-
],
|
|
2151
|
-
outputs=[deltas],
|
|
2152
|
-
device=model.device,
|
|
2153
|
-
)
|
|
3121
|
+
body_q, body_qd = self.apply_body_deltas(model, state_in, state_out, body_deltas, dt)
|
|
2154
3122
|
|
|
2155
|
-
#
|
|
2156
|
-
if model.
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
particle_qd,
|
|
2163
|
-
model.particle_inv_mass,
|
|
2164
|
-
model.spring_indices,
|
|
2165
|
-
model.spring_rest_length,
|
|
2166
|
-
model.spring_stiffness,
|
|
2167
|
-
model.spring_damping,
|
|
2168
|
-
dt,
|
|
2169
|
-
model.spring_constraint_lambdas,
|
|
2170
|
-
],
|
|
2171
|
-
outputs=[deltas],
|
|
2172
|
-
device=model.device,
|
|
2173
|
-
)
|
|
3123
|
+
# Solve rigid contact constraints
|
|
3124
|
+
if model.rigid_contact_max and (
|
|
3125
|
+
model.ground and model.shape_ground_contact_pair_count or model.shape_contact_pair_count
|
|
3126
|
+
):
|
|
3127
|
+
if self.rigid_contact_con_weighting:
|
|
3128
|
+
rigid_contact_inv_weight.zero_()
|
|
3129
|
+
body_deltas.zero_()
|
|
2174
3130
|
|
|
2175
|
-
# bending constraints
|
|
2176
|
-
if model.edge_count:
|
|
2177
3131
|
wp.launch(
|
|
2178
|
-
kernel=
|
|
2179
|
-
dim=model.
|
|
3132
|
+
kernel=solve_body_contact_positions,
|
|
3133
|
+
dim=model.rigid_contact_max,
|
|
2180
3134
|
inputs=[
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
model.
|
|
2184
|
-
model.
|
|
2185
|
-
model.
|
|
2186
|
-
model.
|
|
3135
|
+
body_q,
|
|
3136
|
+
body_qd,
|
|
3137
|
+
model.body_com,
|
|
3138
|
+
model.body_inv_mass,
|
|
3139
|
+
model.body_inv_inertia,
|
|
3140
|
+
model.shape_body,
|
|
3141
|
+
model.rigid_contact_count,
|
|
3142
|
+
model.rigid_contact_point0,
|
|
3143
|
+
model.rigid_contact_point1,
|
|
3144
|
+
model.rigid_contact_offset0,
|
|
3145
|
+
model.rigid_contact_offset1,
|
|
3146
|
+
model.rigid_contact_normal,
|
|
3147
|
+
model.rigid_contact_thickness,
|
|
3148
|
+
model.rigid_contact_shape0,
|
|
3149
|
+
model.rigid_contact_shape1,
|
|
3150
|
+
model.shape_materials,
|
|
3151
|
+
self.rigid_contact_relaxation,
|
|
2187
3152
|
dt,
|
|
2188
|
-
model.
|
|
3153
|
+
model.rigid_contact_torsional_friction,
|
|
3154
|
+
model.rigid_contact_rolling_friction,
|
|
2189
3155
|
],
|
|
2190
|
-
outputs=[
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
# tetrahedral FEM
|
|
2195
|
-
if model.tet_count:
|
|
2196
|
-
wp.launch(
|
|
2197
|
-
kernel=solve_tetrahedra,
|
|
2198
|
-
dim=model.tet_count,
|
|
2199
|
-
inputs=[
|
|
2200
|
-
particle_q,
|
|
2201
|
-
particle_qd,
|
|
2202
|
-
model.particle_inv_mass,
|
|
2203
|
-
model.tet_indices,
|
|
2204
|
-
model.tet_poses,
|
|
2205
|
-
model.tet_activations,
|
|
2206
|
-
model.tet_materials,
|
|
2207
|
-
dt,
|
|
2208
|
-
self.soft_body_relaxation,
|
|
3156
|
+
outputs=[
|
|
3157
|
+
body_deltas,
|
|
3158
|
+
rigid_contact_inv_weight,
|
|
2209
3159
|
],
|
|
2210
|
-
outputs=[deltas],
|
|
2211
3160
|
device=model.device,
|
|
2212
3161
|
)
|
|
2213
3162
|
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
new_particle_qd = particle_qd
|
|
2221
|
-
|
|
2222
|
-
wp.launch(
|
|
2223
|
-
kernel=apply_particle_deltas,
|
|
2224
|
-
dim=model.particle_count,
|
|
2225
|
-
inputs=[
|
|
2226
|
-
state_in.particle_q,
|
|
2227
|
-
particle_q,
|
|
2228
|
-
model.particle_flags,
|
|
2229
|
-
deltas,
|
|
2230
|
-
dt,
|
|
2231
|
-
model.particle_max_velocity,
|
|
2232
|
-
],
|
|
2233
|
-
outputs=[new_particle_q, new_particle_qd],
|
|
2234
|
-
device=model.device,
|
|
2235
|
-
)
|
|
2236
|
-
|
|
2237
|
-
if requires_grad:
|
|
2238
|
-
particle_q.assign(new_particle_q)
|
|
2239
|
-
particle_qd.assign(new_particle_qd)
|
|
2240
|
-
else:
|
|
2241
|
-
particle_q = new_particle_q
|
|
2242
|
-
particle_qd = new_particle_qd
|
|
2243
|
-
|
|
2244
|
-
# handle rigid bodies
|
|
2245
|
-
# ----------------------------
|
|
3163
|
+
# if model.rigid_contact_count.numpy()[0] > 0:
|
|
3164
|
+
# print("rigid_contact_count:", model.rigid_contact_count.numpy().flatten())
|
|
3165
|
+
# # print("rigid_active_contact_distance:", rigid_active_contact_distance.numpy().flatten())
|
|
3166
|
+
# # print("rigid_active_contact_point0:", rigid_active_contact_point0.numpy().flatten())
|
|
3167
|
+
# # print("rigid_active_contact_point1:", rigid_active_contact_point1.numpy().flatten())
|
|
3168
|
+
# print("body_deltas:", body_deltas.numpy().flatten())
|
|
2246
3169
|
|
|
2247
|
-
|
|
2248
|
-
wp.launch(
|
|
2249
|
-
kernel=solve_body_joints,
|
|
2250
|
-
dim=model.joint_count,
|
|
2251
|
-
inputs=[
|
|
2252
|
-
state_out.body_q,
|
|
2253
|
-
state_out.body_qd,
|
|
2254
|
-
model.body_com,
|
|
2255
|
-
model.body_inv_mass,
|
|
2256
|
-
model.body_inv_inertia,
|
|
2257
|
-
model.joint_type,
|
|
2258
|
-
model.joint_enabled,
|
|
2259
|
-
model.joint_parent,
|
|
2260
|
-
model.joint_child,
|
|
2261
|
-
model.joint_X_p,
|
|
2262
|
-
model.joint_X_c,
|
|
2263
|
-
model.joint_limit_lower,
|
|
2264
|
-
model.joint_limit_upper,
|
|
2265
|
-
model.joint_axis_start,
|
|
2266
|
-
model.joint_axis_dim,
|
|
2267
|
-
model.joint_axis_mode,
|
|
2268
|
-
model.joint_axis,
|
|
2269
|
-
model.joint_target,
|
|
2270
|
-
model.joint_target_ke,
|
|
2271
|
-
model.joint_target_kd,
|
|
2272
|
-
model.joint_linear_compliance,
|
|
2273
|
-
model.joint_angular_compliance,
|
|
2274
|
-
self.joint_angular_relaxation,
|
|
2275
|
-
self.joint_linear_relaxation,
|
|
2276
|
-
dt,
|
|
2277
|
-
],
|
|
2278
|
-
outputs=[state_out.body_deltas],
|
|
2279
|
-
device=model.device,
|
|
2280
|
-
)
|
|
3170
|
+
# print(rigid_active_contact_distance.numpy().flatten())
|
|
2281
3171
|
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
state_out.body_qd,
|
|
2289
|
-
model.body_com,
|
|
2290
|
-
model.body_inertia,
|
|
2291
|
-
model.body_inv_mass,
|
|
2292
|
-
model.body_inv_inertia,
|
|
2293
|
-
state_out.body_deltas,
|
|
2294
|
-
None,
|
|
2295
|
-
dt,
|
|
2296
|
-
],
|
|
2297
|
-
outputs=[
|
|
2298
|
-
out_body_q,
|
|
2299
|
-
out_body_qd,
|
|
2300
|
-
],
|
|
2301
|
-
device=model.device,
|
|
2302
|
-
)
|
|
3172
|
+
if self.enable_restitution and i == 0:
|
|
3173
|
+
# remember contact constraint weighting from the first iteration
|
|
3174
|
+
if self.rigid_contact_con_weighting:
|
|
3175
|
+
rigid_contact_inv_weight_init = wp.clone(rigid_contact_inv_weight)
|
|
3176
|
+
else:
|
|
3177
|
+
rigid_contact_inv_weight_init = None
|
|
2303
3178
|
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
state_out.body_q.assign(out_body_q)
|
|
2307
|
-
state_out.body_qd.assign(out_body_qd)
|
|
2308
|
-
|
|
2309
|
-
# Solve rigid contact constraints
|
|
2310
|
-
if model.rigid_contact_max and (
|
|
2311
|
-
model.ground and model.shape_ground_contact_pair_count or model.shape_contact_pair_count
|
|
2312
|
-
):
|
|
2313
|
-
rigid_contact_inv_weight = None
|
|
2314
|
-
if requires_grad:
|
|
2315
|
-
body_deltas = wp.zeros_like(state_out.body_deltas)
|
|
2316
|
-
rigid_active_contact_distance = wp.zeros_like(model.rigid_active_contact_distance)
|
|
2317
|
-
rigid_active_contact_point0 = wp.empty_like(
|
|
2318
|
-
model.rigid_active_contact_point0, requires_grad=True
|
|
2319
|
-
)
|
|
2320
|
-
rigid_active_contact_point1 = wp.empty_like(
|
|
2321
|
-
model.rigid_active_contact_point1, requires_grad=True
|
|
3179
|
+
body_q, body_qd = self.apply_body_deltas(
|
|
3180
|
+
model, state_in, state_out, body_deltas, dt, rigid_contact_inv_weight
|
|
2322
3181
|
)
|
|
2323
|
-
if self.rigid_contact_con_weighting:
|
|
2324
|
-
rigid_contact_inv_weight = wp.zeros_like(model.rigid_contact_inv_weight)
|
|
2325
|
-
else:
|
|
2326
|
-
body_deltas = state_out.body_deltas
|
|
2327
|
-
body_deltas.zero_()
|
|
2328
|
-
rigid_active_contact_distance = model.rigid_active_contact_distance
|
|
2329
|
-
rigid_active_contact_point0 = model.rigid_active_contact_point0
|
|
2330
|
-
rigid_active_contact_point1 = model.rigid_active_contact_point1
|
|
2331
|
-
rigid_active_contact_distance.zero_()
|
|
2332
|
-
if self.rigid_contact_con_weighting:
|
|
2333
|
-
rigid_contact_inv_weight = model.rigid_contact_inv_weight
|
|
2334
|
-
rigid_contact_inv_weight.zero_()
|
|
2335
3182
|
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
state_out.body_q,
|
|
2341
|
-
state_out.body_qd,
|
|
2342
|
-
model.body_com,
|
|
2343
|
-
model.body_inv_mass,
|
|
2344
|
-
model.body_inv_inertia,
|
|
2345
|
-
model.rigid_contact_count,
|
|
2346
|
-
model.rigid_contact_body0,
|
|
2347
|
-
model.rigid_contact_body1,
|
|
2348
|
-
model.rigid_contact_point0,
|
|
2349
|
-
model.rigid_contact_point1,
|
|
2350
|
-
model.rigid_contact_offset0,
|
|
2351
|
-
model.rigid_contact_offset1,
|
|
2352
|
-
model.rigid_contact_normal,
|
|
2353
|
-
model.rigid_contact_thickness,
|
|
2354
|
-
model.rigid_contact_shape0,
|
|
2355
|
-
model.rigid_contact_shape1,
|
|
2356
|
-
model.shape_materials,
|
|
2357
|
-
self.rigid_contact_relaxation,
|
|
2358
|
-
dt,
|
|
2359
|
-
model.rigid_contact_torsional_friction,
|
|
2360
|
-
model.rigid_contact_rolling_friction,
|
|
2361
|
-
],
|
|
2362
|
-
outputs=[
|
|
2363
|
-
body_deltas,
|
|
2364
|
-
rigid_active_contact_point0,
|
|
2365
|
-
rigid_active_contact_point1,
|
|
2366
|
-
rigid_active_contact_distance,
|
|
2367
|
-
rigid_contact_inv_weight,
|
|
2368
|
-
],
|
|
2369
|
-
device=model.device,
|
|
2370
|
-
)
|
|
2371
|
-
|
|
2372
|
-
if self.enable_restitution and i == 0:
|
|
2373
|
-
# remember the contacts from the first iteration
|
|
2374
|
-
if requires_grad:
|
|
2375
|
-
model.rigid_active_contact_distance_prev = wp.clone(rigid_active_contact_distance)
|
|
2376
|
-
model.rigid_active_contact_point0_prev = wp.clone(rigid_active_contact_point0)
|
|
2377
|
-
model.rigid_active_contact_point1_prev = wp.clone(rigid_active_contact_point1)
|
|
2378
|
-
if self.rigid_contact_con_weighting:
|
|
2379
|
-
model.rigid_contact_inv_weight_prev = wp.clone(rigid_contact_inv_weight)
|
|
2380
|
-
else:
|
|
2381
|
-
model.rigid_contact_inv_weight_prev = None
|
|
2382
|
-
else:
|
|
2383
|
-
model.rigid_active_contact_distance_prev.assign(rigid_active_contact_distance)
|
|
2384
|
-
model.rigid_active_contact_point0_prev.assign(rigid_active_contact_point0)
|
|
2385
|
-
model.rigid_active_contact_point1_prev.assign(rigid_active_contact_point1)
|
|
2386
|
-
if self.rigid_contact_con_weighting:
|
|
2387
|
-
model.rigid_contact_inv_weight_prev.assign(rigid_contact_inv_weight)
|
|
2388
|
-
else:
|
|
2389
|
-
model.rigid_contact_inv_weight_prev = None
|
|
2390
|
-
|
|
2391
|
-
if requires_grad:
|
|
2392
|
-
model.rigid_active_contact_distance = rigid_active_contact_distance
|
|
2393
|
-
model.rigid_active_contact_point0 = rigid_active_contact_point0
|
|
2394
|
-
model.rigid_active_contact_point1 = rigid_active_contact_point1
|
|
2395
|
-
body_q = wp.clone(state_out.body_q)
|
|
2396
|
-
body_qd = wp.clone(state_out.body_qd)
|
|
2397
|
-
else:
|
|
2398
|
-
body_q = state_out.body_q
|
|
2399
|
-
body_qd = state_out.body_qd
|
|
2400
|
-
|
|
2401
|
-
# apply updates
|
|
2402
|
-
wp.launch(
|
|
2403
|
-
kernel=apply_body_deltas,
|
|
2404
|
-
dim=model.body_count,
|
|
2405
|
-
inputs=[
|
|
2406
|
-
state_out.body_q,
|
|
2407
|
-
state_out.body_qd,
|
|
2408
|
-
model.body_com,
|
|
2409
|
-
model.body_inertia,
|
|
2410
|
-
model.body_inv_mass,
|
|
2411
|
-
model.body_inv_inertia,
|
|
2412
|
-
body_deltas,
|
|
2413
|
-
rigid_contact_inv_weight,
|
|
2414
|
-
dt,
|
|
2415
|
-
],
|
|
2416
|
-
outputs=[
|
|
2417
|
-
body_q,
|
|
2418
|
-
body_qd,
|
|
2419
|
-
],
|
|
2420
|
-
device=model.device,
|
|
2421
|
-
)
|
|
3183
|
+
if model.particle_count:
|
|
3184
|
+
if particle_q.ptr != state_out.particle_q.ptr:
|
|
3185
|
+
state_out.particle_q.assign(particle_q)
|
|
3186
|
+
state_out.particle_qd.assign(particle_qd)
|
|
2422
3187
|
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
3188
|
+
if model.body_count:
|
|
3189
|
+
if body_q.ptr != state_out.body_q.ptr:
|
|
3190
|
+
state_out.body_q.assign(body_q)
|
|
3191
|
+
state_out.body_qd.assign(body_qd)
|
|
2426
3192
|
|
|
2427
3193
|
# update body velocities from position changes
|
|
2428
|
-
if model.body_count and not requires_grad:
|
|
3194
|
+
if self.compute_body_velocity_from_position_delta and model.body_count and not requires_grad:
|
|
2429
3195
|
# causes gradient issues (probably due to numerical problems
|
|
2430
3196
|
# when computing velocities from position changes)
|
|
2431
3197
|
if requires_grad:
|
|
@@ -2437,78 +3203,98 @@ class XPBDIntegrator:
|
|
|
2437
3203
|
wp.launch(
|
|
2438
3204
|
kernel=update_body_velocities,
|
|
2439
3205
|
dim=model.body_count,
|
|
2440
|
-
inputs=[state_out.body_q,
|
|
3206
|
+
inputs=[state_out.body_q, body_q_init, model.body_com, dt],
|
|
2441
3207
|
outputs=[out_body_qd],
|
|
2442
3208
|
device=model.device,
|
|
2443
3209
|
)
|
|
2444
3210
|
|
|
2445
|
-
if requires_grad:
|
|
2446
|
-
state_out.body_qd.assign(out_body_qd)
|
|
2447
|
-
|
|
2448
3211
|
if self.enable_restitution:
|
|
2449
3212
|
if model.particle_count:
|
|
2450
|
-
if requires_grad:
|
|
2451
|
-
new_particle_qd = wp.clone(particle_qd)
|
|
2452
|
-
else:
|
|
2453
|
-
new_particle_qd = particle_qd
|
|
2454
|
-
|
|
2455
3213
|
wp.launch(
|
|
2456
|
-
kernel=
|
|
3214
|
+
kernel=apply_particle_shape_restitution,
|
|
2457
3215
|
dim=model.particle_count,
|
|
2458
3216
|
inputs=[
|
|
2459
3217
|
particle_q,
|
|
2460
3218
|
particle_qd,
|
|
2461
|
-
|
|
2462
|
-
|
|
3219
|
+
self.particle_q_init,
|
|
3220
|
+
self.particle_qd_init,
|
|
2463
3221
|
model.particle_inv_mass,
|
|
2464
3222
|
model.particle_radius,
|
|
2465
3223
|
model.particle_flags,
|
|
3224
|
+
body_q,
|
|
3225
|
+
body_qd,
|
|
3226
|
+
model.body_com,
|
|
3227
|
+
model.body_inv_mass,
|
|
3228
|
+
model.body_inv_inertia,
|
|
3229
|
+
model.shape_body,
|
|
3230
|
+
model.shape_materials,
|
|
3231
|
+
model.particle_adhesion,
|
|
2466
3232
|
model.soft_contact_restitution,
|
|
2467
|
-
model.
|
|
3233
|
+
model.soft_contact_count,
|
|
3234
|
+
model.soft_contact_particle,
|
|
3235
|
+
model.soft_contact_shape,
|
|
3236
|
+
model.soft_contact_body_pos,
|
|
3237
|
+
model.soft_contact_body_vel,
|
|
3238
|
+
model.soft_contact_normal,
|
|
3239
|
+
model.soft_contact_max,
|
|
2468
3240
|
dt,
|
|
2469
3241
|
self.soft_contact_relaxation,
|
|
2470
3242
|
],
|
|
2471
|
-
outputs=[
|
|
3243
|
+
outputs=[state_out.particle_qd],
|
|
2472
3244
|
device=model.device,
|
|
2473
3245
|
)
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
3246
|
+
if model.ground:
|
|
3247
|
+
wp.launch(
|
|
3248
|
+
kernel=apply_particle_ground_restitution,
|
|
3249
|
+
dim=model.particle_count,
|
|
3250
|
+
inputs=[
|
|
3251
|
+
particle_q,
|
|
3252
|
+
particle_qd,
|
|
3253
|
+
self.particle_q_init,
|
|
3254
|
+
self.particle_qd_init,
|
|
3255
|
+
model.particle_inv_mass,
|
|
3256
|
+
model.particle_radius,
|
|
3257
|
+
model.particle_flags,
|
|
3258
|
+
model.particle_adhesion,
|
|
3259
|
+
model.soft_contact_restitution,
|
|
3260
|
+
model.ground_plane,
|
|
3261
|
+
dt,
|
|
3262
|
+
self.soft_contact_relaxation,
|
|
3263
|
+
],
|
|
3264
|
+
outputs=[state_out.particle_qd],
|
|
3265
|
+
device=model.device,
|
|
3266
|
+
)
|
|
2479
3267
|
|
|
2480
3268
|
if model.body_count:
|
|
2481
|
-
|
|
2482
|
-
state_out.body_deltas = wp.zeros_like(state_out.body_deltas)
|
|
2483
|
-
else:
|
|
2484
|
-
state_out.body_deltas.zero_()
|
|
3269
|
+
body_deltas.zero_()
|
|
2485
3270
|
wp.launch(
|
|
2486
3271
|
kernel=apply_rigid_restitution,
|
|
2487
3272
|
dim=model.rigid_contact_max,
|
|
2488
3273
|
inputs=[
|
|
2489
3274
|
state_out.body_q,
|
|
2490
3275
|
state_out.body_qd,
|
|
2491
|
-
|
|
2492
|
-
|
|
3276
|
+
body_q_init,
|
|
3277
|
+
body_qd_init,
|
|
2493
3278
|
model.body_com,
|
|
2494
3279
|
model.body_inv_mass,
|
|
2495
3280
|
model.body_inv_inertia,
|
|
3281
|
+
model.shape_body,
|
|
2496
3282
|
model.rigid_contact_count,
|
|
2497
|
-
model.rigid_contact_body0,
|
|
2498
|
-
model.rigid_contact_body1,
|
|
2499
3283
|
model.rigid_contact_normal,
|
|
2500
3284
|
model.rigid_contact_shape0,
|
|
2501
3285
|
model.rigid_contact_shape1,
|
|
2502
3286
|
model.shape_materials,
|
|
2503
|
-
model.
|
|
2504
|
-
model.
|
|
2505
|
-
model.
|
|
2506
|
-
model.
|
|
3287
|
+
model.rigid_contact_point0,
|
|
3288
|
+
model.rigid_contact_point1,
|
|
3289
|
+
model.rigid_contact_offset0,
|
|
3290
|
+
model.rigid_contact_offset1,
|
|
3291
|
+
model.rigid_contact_thickness,
|
|
3292
|
+
rigid_contact_inv_weight_init,
|
|
2507
3293
|
model.gravity,
|
|
2508
3294
|
dt,
|
|
2509
3295
|
],
|
|
2510
3296
|
outputs=[
|
|
2511
|
-
|
|
3297
|
+
body_deltas,
|
|
2512
3298
|
],
|
|
2513
3299
|
device=model.device,
|
|
2514
3300
|
)
|
|
@@ -2517,16 +3303,10 @@ class XPBDIntegrator:
|
|
|
2517
3303
|
kernel=apply_body_delta_velocities,
|
|
2518
3304
|
dim=model.body_count,
|
|
2519
3305
|
inputs=[
|
|
2520
|
-
|
|
2521
|
-
state_out.body_deltas,
|
|
3306
|
+
body_deltas,
|
|
2522
3307
|
],
|
|
2523
3308
|
outputs=[state_out.body_qd],
|
|
2524
3309
|
device=model.device,
|
|
2525
3310
|
)
|
|
2526
3311
|
|
|
2527
|
-
if model.particle_count:
|
|
2528
|
-
# update particle state
|
|
2529
|
-
state_out.particle_q.assign(particle_q)
|
|
2530
|
-
state_out.particle_qd.assign(particle_qd)
|
|
2531
|
-
|
|
2532
3312
|
return state_out
|