warp-lang 1.6.2__py3-none-win_amd64.whl → 1.7.0__py3-none-win_amd64.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 +7 -1
- warp/bin/warp-clang.dll +0 -0
- warp/bin/warp.dll +0 -0
- warp/build.py +410 -0
- warp/build_dll.py +6 -14
- warp/builtins.py +452 -362
- warp/codegen.py +179 -119
- warp/config.py +42 -6
- warp/context.py +490 -271
- warp/dlpack.py +8 -6
- warp/examples/assets/nonuniform.usd +0 -0
- warp/examples/assets/nvidia_logo.png +0 -0
- warp/examples/benchmarks/benchmark_tile_load_store.py +103 -0
- warp/examples/core/example_sample_mesh.py +300 -0
- warp/examples/fem/example_apic_fluid.py +1 -1
- warp/examples/fem/example_burgers.py +2 -2
- warp/examples/fem/example_deformed_geometry.py +1 -1
- warp/examples/fem/example_distortion_energy.py +1 -1
- warp/examples/fem/example_magnetostatics.py +6 -6
- warp/examples/fem/utils.py +9 -3
- warp/examples/interop/example_jax_callable.py +116 -0
- warp/examples/interop/example_jax_ffi_callback.py +132 -0
- warp/examples/interop/example_jax_kernel.py +205 -0
- warp/examples/optim/example_fluid_checkpoint.py +497 -0
- warp/examples/tile/example_tile_matmul.py +2 -4
- warp/fem/__init__.py +11 -1
- warp/fem/adaptivity.py +4 -4
- warp/fem/field/nodal_field.py +22 -68
- warp/fem/field/virtual.py +62 -23
- warp/fem/geometry/adaptive_nanogrid.py +9 -10
- warp/fem/geometry/closest_point.py +1 -1
- warp/fem/geometry/deformed_geometry.py +5 -2
- warp/fem/geometry/geometry.py +5 -0
- warp/fem/geometry/grid_2d.py +12 -12
- warp/fem/geometry/grid_3d.py +12 -15
- warp/fem/geometry/hexmesh.py +5 -7
- warp/fem/geometry/nanogrid.py +9 -11
- warp/fem/geometry/quadmesh.py +13 -13
- warp/fem/geometry/tetmesh.py +3 -4
- warp/fem/geometry/trimesh.py +3 -8
- warp/fem/integrate.py +262 -93
- warp/fem/linalg.py +5 -5
- warp/fem/quadrature/pic_quadrature.py +37 -22
- warp/fem/quadrature/quadrature.py +194 -25
- warp/fem/space/__init__.py +1 -1
- warp/fem/space/basis_function_space.py +4 -2
- warp/fem/space/basis_space.py +25 -18
- warp/fem/space/hexmesh_function_space.py +2 -2
- warp/fem/space/partition.py +6 -2
- warp/fem/space/quadmesh_function_space.py +8 -8
- warp/fem/space/shape/cube_shape_function.py +23 -23
- warp/fem/space/shape/square_shape_function.py +12 -12
- warp/fem/space/shape/triangle_shape_function.py +1 -1
- warp/fem/space/tetmesh_function_space.py +3 -3
- warp/fem/space/trimesh_function_space.py +2 -2
- warp/fem/utils.py +12 -6
- warp/jax.py +14 -1
- warp/jax_experimental/__init__.py +16 -0
- warp/{jax_experimental.py → jax_experimental/custom_call.py} +14 -27
- warp/jax_experimental/ffi.py +698 -0
- warp/jax_experimental/xla_ffi.py +602 -0
- warp/math.py +89 -0
- warp/native/array.h +13 -0
- warp/native/builtin.h +29 -3
- warp/native/bvh.cpp +3 -1
- warp/native/bvh.cu +42 -14
- warp/native/bvh.h +2 -1
- warp/native/clang/clang.cpp +30 -3
- warp/native/cuda_util.cpp +14 -0
- warp/native/cuda_util.h +2 -0
- warp/native/exports.h +68 -63
- warp/native/intersect.h +26 -26
- warp/native/intersect_adj.h +33 -33
- warp/native/marching.cu +1 -1
- warp/native/mat.h +513 -9
- warp/native/mesh.h +10 -10
- warp/native/quat.h +99 -11
- warp/native/rand.h +6 -0
- warp/native/sort.cpp +122 -59
- warp/native/sort.cu +152 -15
- warp/native/sort.h +8 -1
- warp/native/sparse.cpp +43 -22
- warp/native/sparse.cu +52 -17
- warp/native/svd.h +116 -0
- warp/native/tile.h +301 -105
- warp/native/tile_reduce.h +46 -3
- warp/native/vec.h +68 -7
- warp/native/volume.cpp +85 -113
- warp/native/volume_builder.cu +25 -10
- warp/native/volume_builder.h +6 -0
- warp/native/warp.cpp +5 -6
- warp/native/warp.cu +99 -10
- warp/native/warp.h +19 -10
- warp/optim/linear.py +10 -10
- warp/sim/articulation.py +4 -4
- warp/sim/collide.py +21 -10
- warp/sim/import_mjcf.py +449 -155
- warp/sim/import_urdf.py +32 -12
- warp/sim/integrator_euler.py +5 -5
- warp/sim/integrator_featherstone.py +3 -10
- warp/sim/integrator_vbd.py +207 -2
- warp/sim/integrator_xpbd.py +5 -5
- warp/sim/model.py +42 -13
- warp/sim/utils.py +2 -2
- warp/sparse.py +642 -555
- warp/stubs.py +216 -19
- warp/tests/__main__.py +0 -15
- warp/tests/cuda/__init__.py +0 -0
- warp/tests/{test_mempool.py → cuda/test_mempool.py} +39 -0
- warp/tests/{test_streams.py → cuda/test_streams.py} +71 -0
- warp/tests/geometry/__init__.py +0 -0
- warp/tests/{test_mesh_query_point.py → geometry/test_mesh_query_point.py} +66 -63
- warp/tests/{test_mesh_query_ray.py → geometry/test_mesh_query_ray.py} +1 -1
- warp/tests/{test_volume.py → geometry/test_volume.py} +41 -6
- warp/tests/interop/__init__.py +0 -0
- warp/tests/{test_dlpack.py → interop/test_dlpack.py} +28 -5
- warp/tests/sim/__init__.py +0 -0
- warp/tests/{disabled_kinematics.py → sim/disabled_kinematics.py} +9 -10
- warp/tests/{test_collision.py → sim/test_collision.py} +2 -2
- warp/tests/{test_model.py → sim/test_model.py} +40 -0
- warp/tests/{test_sim_kinematics.py → sim/test_sim_kinematics.py} +2 -1
- warp/tests/sim/test_vbd.py +597 -0
- warp/tests/test_bool.py +1 -1
- warp/tests/test_examples.py +28 -36
- warp/tests/test_fem.py +23 -4
- warp/tests/test_linear_solvers.py +0 -11
- warp/tests/test_mat.py +233 -79
- warp/tests/test_mat_scalar_ops.py +4 -4
- warp/tests/test_overwrite.py +0 -60
- warp/tests/test_quat.py +67 -46
- warp/tests/test_rand.py +44 -37
- warp/tests/test_sparse.py +47 -6
- warp/tests/test_spatial.py +75 -0
- warp/tests/test_static.py +1 -1
- warp/tests/test_utils.py +84 -4
- warp/tests/test_vec.py +46 -34
- warp/tests/tile/__init__.py +0 -0
- warp/tests/{test_tile.py → tile/test_tile.py} +136 -51
- warp/tests/{test_tile_load.py → tile/test_tile_load.py} +1 -1
- warp/tests/{test_tile_mathdx.py → tile/test_tile_mathdx.py} +9 -6
- warp/tests/{test_tile_mlp.py → tile/test_tile_mlp.py} +25 -14
- warp/tests/{test_tile_reduce.py → tile/test_tile_reduce.py} +60 -1
- warp/tests/{test_tile_view.py → tile/test_tile_view.py} +1 -1
- warp/tests/unittest_serial.py +1 -0
- warp/tests/unittest_suites.py +45 -59
- warp/tests/unittest_utils.py +2 -1
- warp/thirdparty/unittest_parallel.py +3 -1
- warp/types.py +110 -658
- warp/utils.py +137 -72
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.0.dist-info}/METADATA +29 -7
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.0.dist-info}/RECORD +172 -162
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.0.dist-info}/WHEEL +1 -1
- warp/examples/optim/example_walker.py +0 -317
- warp/native/cutlass_gemm.cpp +0 -43
- warp/native/cutlass_gemm.cu +0 -382
- warp/tests/test_matmul.py +0 -511
- warp/tests/test_matmul_lite.py +0 -411
- warp/tests/test_vbd.py +0 -386
- warp/tests/unused_test_misc.py +0 -77
- /warp/tests/{test_async.py → cuda/test_async.py} +0 -0
- /warp/tests/{test_ipc.py → cuda/test_ipc.py} +0 -0
- /warp/tests/{test_multigpu.py → cuda/test_multigpu.py} +0 -0
- /warp/tests/{test_peer.py → cuda/test_peer.py} +0 -0
- /warp/tests/{test_pinned.py → cuda/test_pinned.py} +0 -0
- /warp/tests/{test_bvh.py → geometry/test_bvh.py} +0 -0
- /warp/tests/{test_hash_grid.py → geometry/test_hash_grid.py} +0 -0
- /warp/tests/{test_marching_cubes.py → geometry/test_marching_cubes.py} +0 -0
- /warp/tests/{test_mesh.py → geometry/test_mesh.py} +0 -0
- /warp/tests/{test_mesh_query_aabb.py → geometry/test_mesh_query_aabb.py} +0 -0
- /warp/tests/{test_volume_write.py → geometry/test_volume_write.py} +0 -0
- /warp/tests/{test_jax.py → interop/test_jax.py} +0 -0
- /warp/tests/{test_paddle.py → interop/test_paddle.py} +0 -0
- /warp/tests/{test_torch.py → interop/test_torch.py} +0 -0
- /warp/tests/{flaky_test_sim_grad.py → sim/flaky_test_sim_grad.py} +0 -0
- /warp/tests/{test_coloring.py → sim/test_coloring.py} +0 -0
- /warp/tests/{test_sim_grad_bounce_linear.py → sim/test_sim_grad_bounce_linear.py} +0 -0
- /warp/tests/{test_tile_shared_memory.py → tile/test_tile_shared_memory.py} +0 -0
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.0.dist-info/licenses}/LICENSE.md +0 -0
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.0.dist-info}/top_level.txt +0 -0
warp/sim/import_urdf.py
CHANGED
|
@@ -20,7 +20,6 @@ from typing import Union
|
|
|
20
20
|
import numpy as np
|
|
21
21
|
|
|
22
22
|
import warp as wp
|
|
23
|
-
import warp.sim
|
|
24
23
|
from warp.sim.model import Mesh
|
|
25
24
|
|
|
26
25
|
|
|
@@ -46,6 +45,7 @@ def parse_urdf(
|
|
|
46
45
|
joint_limit_lower=-1e6,
|
|
47
46
|
joint_limit_upper=1e6,
|
|
48
47
|
scale=1.0,
|
|
48
|
+
hide_visuals=False,
|
|
49
49
|
parse_visuals_as_colliders=False,
|
|
50
50
|
force_show_colliders=False,
|
|
51
51
|
enable_self_collisions=True,
|
|
@@ -79,6 +79,7 @@ def parse_urdf(
|
|
|
79
79
|
joint_limit_lower (float): The default lower joint limit if not specified in the URDF.
|
|
80
80
|
joint_limit_upper (float): The default upper joint limit if not specified in the URDF.
|
|
81
81
|
scale (float): The scaling factor to apply to the imported mechanism.
|
|
82
|
+
hide_visuals (bool): If True, hide visual shapes.
|
|
82
83
|
parse_visuals_as_colliders (bool): If True, the geometry defined under the `<visual>` tags is used for collision handling instead of the `<collision>` geometries.
|
|
83
84
|
force_show_colliders (bool): If True, the collision shapes are always shown, even if there are visual shapes.
|
|
84
85
|
enable_self_collisions (bool): If True, self-collisions are enabled.
|
|
@@ -173,6 +174,22 @@ def parse_urdf(
|
|
|
173
174
|
)
|
|
174
175
|
shapes.append(s)
|
|
175
176
|
|
|
177
|
+
for capsule in geo.findall("capsule"):
|
|
178
|
+
s = builder.add_shape_capsule(
|
|
179
|
+
body=link,
|
|
180
|
+
pos=wp.vec3(tf.p),
|
|
181
|
+
rot=wp.quat(tf.q),
|
|
182
|
+
radius=float(capsule.get("radius") or "1") * scale,
|
|
183
|
+
half_height=float(capsule.get("height") or "1") * 0.5 * scale,
|
|
184
|
+
density=density,
|
|
185
|
+
up_axis=2, # capsules in URDF are aligned with z-axis
|
|
186
|
+
is_visible=visible,
|
|
187
|
+
has_ground_collision=not just_visual,
|
|
188
|
+
has_shape_collision=not just_visual,
|
|
189
|
+
**contact_vars,
|
|
190
|
+
)
|
|
191
|
+
shapes.append(s)
|
|
192
|
+
|
|
176
193
|
for mesh in geo.findall("mesh"):
|
|
177
194
|
filename = mesh.get("filename")
|
|
178
195
|
if filename is None:
|
|
@@ -219,15 +236,15 @@ def parse_urdf(
|
|
|
219
236
|
scaling = np.array([float(x) * scale for x in scaling.split()])
|
|
220
237
|
if hasattr(m, "geometry"):
|
|
221
238
|
# multiple meshes are contained in a scene
|
|
222
|
-
for
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
239
|
+
for m_geom in m.geometry.values():
|
|
240
|
+
m_vertices = np.array(m_geom.vertices, dtype=np.float32) * scaling
|
|
241
|
+
m_faces = np.array(m_geom.faces.flatten(), dtype=np.int32)
|
|
242
|
+
m_mesh = Mesh(m_vertices, m_faces)
|
|
226
243
|
s = builder.add_shape_mesh(
|
|
227
244
|
body=link,
|
|
228
245
|
pos=wp.vec3(tf.p),
|
|
229
246
|
rot=wp.quat(tf.q),
|
|
230
|
-
mesh=
|
|
247
|
+
mesh=m_mesh,
|
|
231
248
|
density=density,
|
|
232
249
|
is_visible=visible,
|
|
233
250
|
has_ground_collision=not just_visual,
|
|
@@ -278,7 +295,7 @@ def parse_urdf(
|
|
|
278
295
|
if parse_visuals_as_colliders:
|
|
279
296
|
colliders = visuals
|
|
280
297
|
else:
|
|
281
|
-
s = parse_shapes(link, visuals, density=0.0, just_visual=True)
|
|
298
|
+
s = parse_shapes(link, visuals, density=0.0, just_visual=True, visible=not hide_visuals)
|
|
282
299
|
visual_shapes.extend(s)
|
|
283
300
|
|
|
284
301
|
show_colliders = force_show_colliders
|
|
@@ -309,10 +326,13 @@ def parse_urdf(
|
|
|
309
326
|
I_m = rot @ wp.mat33(I_m)
|
|
310
327
|
m = float(inertial.find("mass").get("value") or "0")
|
|
311
328
|
builder.body_mass[link] = m
|
|
312
|
-
builder.body_inv_mass[link] = 1.0 / m
|
|
329
|
+
builder.body_inv_mass[link] = 1.0 / m if m > 0.0 else 0.0
|
|
313
330
|
builder.body_com[link] = com
|
|
314
331
|
builder.body_inertia[link] = I_m
|
|
315
|
-
|
|
332
|
+
if any(x for x in I_m):
|
|
333
|
+
builder.body_inv_inertia[link] = wp.inverse(I_m)
|
|
334
|
+
else:
|
|
335
|
+
builder.body_inv_inertia[link] = I_m
|
|
316
336
|
if m == 0.0 and ensure_nonstatic_links:
|
|
317
337
|
# set the mass to something nonzero to ensure the body is dynamic
|
|
318
338
|
m = static_link_mass
|
|
@@ -369,7 +389,7 @@ def parse_urdf(
|
|
|
369
389
|
|
|
370
390
|
# topological sorting of joints because the FK solver will resolve body transforms
|
|
371
391
|
# in joint order and needs the parent link transform to be resolved before the child
|
|
372
|
-
visited =
|
|
392
|
+
visited = dict.fromkeys(link_index.keys(), False)
|
|
373
393
|
sorted_joints = []
|
|
374
394
|
|
|
375
395
|
# depth-first search
|
|
@@ -520,7 +540,7 @@ def parse_urdf(
|
|
|
520
540
|
|
|
521
541
|
builder.add_joint_d6(
|
|
522
542
|
linear_axes=[
|
|
523
|
-
|
|
543
|
+
wp.sim.JointAxis(
|
|
524
544
|
u,
|
|
525
545
|
limit_lower=lower * scale,
|
|
526
546
|
limit_upper=upper * scale,
|
|
@@ -530,7 +550,7 @@ def parse_urdf(
|
|
|
530
550
|
target_kd=joint_damping,
|
|
531
551
|
mode=joint_mode,
|
|
532
552
|
),
|
|
533
|
-
|
|
553
|
+
wp.sim.JointAxis(
|
|
534
554
|
v,
|
|
535
555
|
limit_lower=lower * scale,
|
|
536
556
|
limit_upper=upper * scale,
|
warp/sim/integrator_euler.py
CHANGED
|
@@ -559,7 +559,7 @@ def eval_tetrahedra(
|
|
|
559
559
|
v20 = v2 - v0
|
|
560
560
|
v30 = v3 - v0
|
|
561
561
|
|
|
562
|
-
Ds = wp.
|
|
562
|
+
Ds = wp.matrix_from_cols(x10, x20, x30)
|
|
563
563
|
Dm = pose[tid]
|
|
564
564
|
|
|
565
565
|
inv_rest_volume = wp.determinant(Dm) * 6.0
|
|
@@ -574,7 +574,7 @@ def eval_tetrahedra(
|
|
|
574
574
|
|
|
575
575
|
# F = Xs*Xm^-1
|
|
576
576
|
F = Ds * Dm
|
|
577
|
-
dFdt = wp.
|
|
577
|
+
dFdt = wp.matrix_from_cols(v10, v20, v30) * Dm
|
|
578
578
|
|
|
579
579
|
col1 = wp.vec3(F[0, 0], F[1, 0], F[2, 0])
|
|
580
580
|
col2 = wp.vec3(F[0, 1], F[1, 1], F[2, 1])
|
|
@@ -660,9 +660,9 @@ def eval_tetrahedra(
|
|
|
660
660
|
|
|
661
661
|
# alpha = 1.0
|
|
662
662
|
|
|
663
|
-
# I = wp.
|
|
664
|
-
#
|
|
665
|
-
#
|
|
663
|
+
# I = wp.matrix_from_cols(wp.vec3(1.0, 0.0, 0.0),
|
|
664
|
+
# wp.vec3(0.0, 1.0, 0.0),
|
|
665
|
+
# wp.vec3(0.0, 0.0, 1.0))
|
|
666
666
|
|
|
667
667
|
# P = (F + wp.transpose(F) + I*(0.0-2.0))*k_mu
|
|
668
668
|
# H = P * wp.transpose(Dm)
|
|
@@ -128,7 +128,7 @@ def spatial_transform_inertia(t: wp.transform, I: wp.spatial_matrix):
|
|
|
128
128
|
r2 = wp.quat_rotate(q, wp.vec3(0.0, 1.0, 0.0))
|
|
129
129
|
r3 = wp.quat_rotate(q, wp.vec3(0.0, 0.0, 1.0))
|
|
130
130
|
|
|
131
|
-
R = wp.
|
|
131
|
+
R = wp.matrix_from_cols(r1, r2, r3)
|
|
132
132
|
S = wp.skew(p) @ R
|
|
133
133
|
|
|
134
134
|
T = spatial_adjoint(R, S)
|
|
@@ -298,7 +298,7 @@ def jcalc_motion(
|
|
|
298
298
|
if type == wp.sim.JOINT_UNIVERSAL:
|
|
299
299
|
axis_0 = joint_axis[axis_start + 0]
|
|
300
300
|
axis_1 = joint_axis[axis_start + 1]
|
|
301
|
-
q_off = wp.quat_from_matrix(wp.
|
|
301
|
+
q_off = wp.quat_from_matrix(wp.matrix_from_cols(axis_0, axis_1, wp.cross(axis_0, axis_1)))
|
|
302
302
|
local_0 = wp.quat_rotate(q_off, wp.vec3(1.0, 0.0, 0.0))
|
|
303
303
|
local_1 = wp.quat_rotate(q_off, wp.vec3(0.0, 1.0, 0.0))
|
|
304
304
|
|
|
@@ -319,7 +319,7 @@ def jcalc_motion(
|
|
|
319
319
|
axis_0 = joint_axis[axis_start + 0]
|
|
320
320
|
axis_1 = joint_axis[axis_start + 1]
|
|
321
321
|
axis_2 = joint_axis[axis_start + 2]
|
|
322
|
-
q_off = wp.quat_from_matrix(wp.
|
|
322
|
+
q_off = wp.quat_from_matrix(wp.matrix_from_cols(axis_0, axis_1, axis_2))
|
|
323
323
|
local_0 = wp.quat_rotate(q_off, wp.vec3(1.0, 0.0, 0.0))
|
|
324
324
|
local_1 = wp.quat_rotate(q_off, wp.vec3(0.0, 1.0, 0.0))
|
|
325
325
|
local_2 = wp.quat_rotate(q_off, wp.vec3(0.0, 0.0, 1.0))
|
|
@@ -2066,13 +2066,6 @@ class FeatherstoneIntegrator(Integrator):
|
|
|
2066
2066
|
],
|
|
2067
2067
|
device=model.device,
|
|
2068
2068
|
)
|
|
2069
|
-
# if wp.context.runtime.tape:
|
|
2070
|
-
# wp.context.runtime.tape.record_func(
|
|
2071
|
-
# backward=lambda: adj_matmul(
|
|
2072
|
-
# a, b, c, a.grad, b.grad, c.grad, d.grad, alpha, beta, allow_tf32x3_arith, device
|
|
2073
|
-
# ),
|
|
2074
|
-
# arrays=[a, b, c, d],
|
|
2075
|
-
# )
|
|
2076
2069
|
# print("joint_qdd:")
|
|
2077
2070
|
# print(state_aug.joint_qdd.numpy())
|
|
2078
2071
|
# print("\n\n")
|
warp/sim/integrator_vbd.py
CHANGED
|
@@ -346,6 +346,172 @@ def evaluate_stvk_force_hessian(
|
|
|
346
346
|
return f, h
|
|
347
347
|
|
|
348
348
|
|
|
349
|
+
@wp.func
|
|
350
|
+
def mat_vec_cross_from_3_basis(e1: wp.vec3, e2: wp.vec3, e3: wp.vec3, a: wp.vec3):
|
|
351
|
+
e1_cross_a = wp.cross(e1, a)
|
|
352
|
+
e2_cross_a = wp.cross(e2, a)
|
|
353
|
+
e3_cross_a = wp.cross(e3, a)
|
|
354
|
+
|
|
355
|
+
return wp.mat33(
|
|
356
|
+
e1_cross_a[0],
|
|
357
|
+
e2_cross_a[0],
|
|
358
|
+
e3_cross_a[0],
|
|
359
|
+
e1_cross_a[1],
|
|
360
|
+
e2_cross_a[1],
|
|
361
|
+
e3_cross_a[1],
|
|
362
|
+
e1_cross_a[2],
|
|
363
|
+
e2_cross_a[2],
|
|
364
|
+
e3_cross_a[2],
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
@wp.func
|
|
369
|
+
def mat_vec_cross(mat: wp.mat33, a: wp.vec3):
|
|
370
|
+
e1 = wp.vec3(mat[0, 0], mat[1, 0], mat[2, 0])
|
|
371
|
+
e2 = wp.vec3(mat[0, 1], mat[1, 1], mat[2, 1])
|
|
372
|
+
e3 = wp.vec3(mat[0, 2], mat[1, 2], mat[2, 2])
|
|
373
|
+
|
|
374
|
+
return mat_vec_cross_from_3_basis(e1, e2, e3, a)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@wp.func
|
|
378
|
+
def evaluate_dihedral_angle_based_bending_force_hessian(
|
|
379
|
+
bending_index: int,
|
|
380
|
+
v_order: int,
|
|
381
|
+
pos: wp.array(dtype=wp.vec3),
|
|
382
|
+
pos_prev: wp.array(dtype=wp.vec3),
|
|
383
|
+
edge_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
384
|
+
edge_rest_angle: wp.array(dtype=float),
|
|
385
|
+
edge_rest_length: wp.array(dtype=float),
|
|
386
|
+
stiffness: float,
|
|
387
|
+
damping: float,
|
|
388
|
+
dt: float,
|
|
389
|
+
):
|
|
390
|
+
if edge_indices[bending_index, 0] == -1 or edge_indices[bending_index, 1] == -1:
|
|
391
|
+
return wp.vec3(0.0), wp.mat33(0.0)
|
|
392
|
+
|
|
393
|
+
x1 = pos[edge_indices[bending_index, 0]]
|
|
394
|
+
x2 = pos[edge_indices[bending_index, 2]]
|
|
395
|
+
x3 = pos[edge_indices[bending_index, 3]]
|
|
396
|
+
x4 = pos[edge_indices[bending_index, 1]]
|
|
397
|
+
|
|
398
|
+
e1 = wp.vec3(1.0, 0.0, 0.0)
|
|
399
|
+
e2 = wp.vec3(0.0, 1.0, 0.0)
|
|
400
|
+
e3 = wp.vec3(0.0, 0.0, 1.0)
|
|
401
|
+
|
|
402
|
+
n1 = wp.cross((x2 - x1), (x3 - x1))
|
|
403
|
+
n2 = wp.cross((x3 - x4), (x2 - x4))
|
|
404
|
+
n1_norm = wp.length(n1)
|
|
405
|
+
n2_norm = wp.length(n2)
|
|
406
|
+
|
|
407
|
+
# degenerated bending edge
|
|
408
|
+
if n1_norm < 1.0e-6 or n2_norm < 1.0e-6:
|
|
409
|
+
return wp.vec3(0.0), wp.mat33(0.0)
|
|
410
|
+
|
|
411
|
+
n1_n = n1 / n1_norm
|
|
412
|
+
n2_n = n2 / n2_norm
|
|
413
|
+
|
|
414
|
+
# avoid the infinite gradient of acos at -1 or 1
|
|
415
|
+
cos_theta = wp.dot(n1_n, n2_n)
|
|
416
|
+
if wp.abs(cos_theta) > 0.9999:
|
|
417
|
+
cos_theta = 0.9999 * wp.sign(cos_theta)
|
|
418
|
+
|
|
419
|
+
angle_sign = wp.sign(wp.dot(wp.cross(n2, n1), x3 - x2))
|
|
420
|
+
theta = wp.acos(cos_theta) * angle_sign
|
|
421
|
+
rest_angle = edge_rest_angle[bending_index]
|
|
422
|
+
|
|
423
|
+
dE_dtheta = stiffness * (theta - rest_angle)
|
|
424
|
+
|
|
425
|
+
d_theta_d_cos_theta = angle_sign * (-1.0 / wp.sqrt(1.0 - cos_theta * cos_theta))
|
|
426
|
+
sin_theta = angle_sign * wp.sqrt(1.0 - cos_theta * cos_theta)
|
|
427
|
+
one_over_sin_theta = 1.0 / sin_theta
|
|
428
|
+
d_one_over_sin_theta_d_cos_theta = cos_theta / (sin_theta * sin_theta * sin_theta)
|
|
429
|
+
|
|
430
|
+
e_rest_len = edge_rest_length[bending_index]
|
|
431
|
+
|
|
432
|
+
if v_order == 0:
|
|
433
|
+
d_cos_theta_dx1 = 1.0 / n1_norm * (-wp.cross(x3 - x1, n2_n) + wp.cross(x2 - x1, n2_n))
|
|
434
|
+
d_one_over_sin_theta_dx1 = d_cos_theta_dx1 * d_one_over_sin_theta_d_cos_theta
|
|
435
|
+
|
|
436
|
+
d_theta_dx1 = d_theta_d_cos_theta * d_cos_theta_dx1
|
|
437
|
+
d2_theta_dx1_dx1 = -wp.outer(d_one_over_sin_theta_dx1, d_cos_theta_dx1)
|
|
438
|
+
|
|
439
|
+
dE_dx1 = e_rest_len * dE_dtheta * d_theta_d_cos_theta * d_cos_theta_dx1
|
|
440
|
+
|
|
441
|
+
d2_E_dx1_dx1 = (
|
|
442
|
+
e_rest_len * stiffness * (wp.outer(d_theta_dx1, d_theta_dx1) + (theta - rest_angle) * d2_theta_dx1_dx1)
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
bending_force = -dE_dx1
|
|
446
|
+
bending_hessian = d2_E_dx1_dx1
|
|
447
|
+
elif v_order == 1:
|
|
448
|
+
d_cos_theta_dx4 = 1.0 / n2_norm * (-wp.cross(x2 - x4, n1_n) + wp.cross(x3 - x4, n1_n))
|
|
449
|
+
d_one_over_sin_theta_dx4 = d_cos_theta_dx4 * d_one_over_sin_theta_d_cos_theta
|
|
450
|
+
|
|
451
|
+
d_theta_dx4 = d_theta_d_cos_theta * d_cos_theta_dx4
|
|
452
|
+
d2_theta_dx4_dx4 = -wp.outer(d_one_over_sin_theta_dx4, d_cos_theta_dx4)
|
|
453
|
+
|
|
454
|
+
dE_dx4 = e_rest_len * dE_dtheta * d_theta_d_cos_theta * d_cos_theta_dx4
|
|
455
|
+
d2_E_dx4_dx4 = (
|
|
456
|
+
e_rest_len * stiffness * (wp.outer(d_theta_dx4, d_theta_dx4) + (theta - rest_angle) * (d2_theta_dx4_dx4))
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
bending_force = -dE_dx4
|
|
460
|
+
bending_hessian = d2_E_dx4_dx4
|
|
461
|
+
elif v_order == 2:
|
|
462
|
+
d_cos_theta_dx2 = 1.0 / n1_norm * wp.cross(x3 - x1, n2_n) - 1.0 / n2_norm * wp.cross(x3 - x4, n1_n)
|
|
463
|
+
dn1_dx2 = mat_vec_cross_from_3_basis(e1, e2, e3, x3 - x1)
|
|
464
|
+
dn2_dx2 = -mat_vec_cross_from_3_basis(e1, e2, e3, x3 - x4)
|
|
465
|
+
d_one_over_sin_theta_dx2 = d_cos_theta_dx2 * d_one_over_sin_theta_d_cos_theta
|
|
466
|
+
d2_cos_theta_dx2_dx2 = -mat_vec_cross(dn2_dx2, (x3 - x1)) / (n1_norm * n2_norm) + mat_vec_cross(
|
|
467
|
+
dn1_dx2, x3 - x4
|
|
468
|
+
) / (n1_norm * n2_norm)
|
|
469
|
+
|
|
470
|
+
d_theta_dx2 = d_theta_d_cos_theta * d_cos_theta_dx2
|
|
471
|
+
d2_theta_dx2_dx2 = (
|
|
472
|
+
-wp.outer(d_one_over_sin_theta_dx2, d_cos_theta_dx2) - one_over_sin_theta * d2_cos_theta_dx2_dx2
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
dE_dx2 = e_rest_len * dE_dtheta * d_theta_d_cos_theta * d_cos_theta_dx2
|
|
476
|
+
d2_E_dx2_dx2 = (
|
|
477
|
+
e_rest_len * stiffness * (wp.outer(d_theta_dx2, d_theta_dx2) + (theta - rest_angle) * d2_theta_dx2_dx2)
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
bending_force = -dE_dx2
|
|
481
|
+
bending_hessian = d2_E_dx2_dx2
|
|
482
|
+
else:
|
|
483
|
+
d_cos_theta_dx3 = -1.0 / n1_norm * wp.cross(x2 - x1, n2_n) + 1.0 / n2_norm * wp.cross(x2 - x4, n1_n)
|
|
484
|
+
dn1_dx3 = -mat_vec_cross_from_3_basis(e1, e2, e3, x2 - x1)
|
|
485
|
+
dn2_dx3 = mat_vec_cross_from_3_basis(e1, e2, e3, x2 - x4)
|
|
486
|
+
d_one_over_sin_theta_dx3 = d_cos_theta_dx3 * d_one_over_sin_theta_d_cos_theta
|
|
487
|
+
d2_cos_theta_dx3_dx3 = mat_vec_cross(dn2_dx3, (x2 - x1)) / (n1_norm * n2_norm) - mat_vec_cross(
|
|
488
|
+
dn1_dx3, x2 - x4
|
|
489
|
+
) / (n1_norm * n2_norm)
|
|
490
|
+
|
|
491
|
+
d_theta_dx3 = d_theta_d_cos_theta * d_cos_theta_dx3
|
|
492
|
+
d2_theta_dx3_dx3 = (
|
|
493
|
+
-wp.outer(d_one_over_sin_theta_dx3, d_cos_theta_dx3) - one_over_sin_theta * d2_cos_theta_dx3_dx3
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
dE_dx3 = e_rest_len * dE_dtheta * d_theta_d_cos_theta * d_cos_theta_dx3
|
|
497
|
+
|
|
498
|
+
d2_E_dx3_dx3 = (
|
|
499
|
+
e_rest_len * stiffness * (wp.outer(d_theta_dx3, d_theta_dx3) + (theta - rest_angle) * d2_theta_dx3_dx3)
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
bending_force = -dE_dx3
|
|
503
|
+
bending_hessian = d2_E_dx3_dx3
|
|
504
|
+
|
|
505
|
+
displacement = pos_prev[edge_indices[bending_index, v_order]] - pos[edge_indices[bending_index, v_order]]
|
|
506
|
+
h_d = bending_hessian * (damping / dt)
|
|
507
|
+
f_d = h_d * displacement
|
|
508
|
+
|
|
509
|
+
bending_force = bending_force + f_d
|
|
510
|
+
bending_hessian = bending_hessian + h_d
|
|
511
|
+
|
|
512
|
+
return bending_force, bending_hessian
|
|
513
|
+
|
|
514
|
+
|
|
349
515
|
@wp.func
|
|
350
516
|
def evaluate_ground_contact_force_hessian(
|
|
351
517
|
particle_pos: wp.vec3,
|
|
@@ -866,6 +1032,9 @@ def VBD_solve_trimesh_no_self_contact(
|
|
|
866
1032
|
tri_materials: wp.array(dtype=float, ndim=2),
|
|
867
1033
|
tri_areas: wp.array(dtype=float),
|
|
868
1034
|
edge_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
1035
|
+
edge_rest_angles: wp.array(dtype=float),
|
|
1036
|
+
edge_rest_length: wp.array(dtype=float),
|
|
1037
|
+
edge_bending_properties: wp.array(dtype=float, ndim=2),
|
|
869
1038
|
adjacency: ForceElementAdjacencyInfo,
|
|
870
1039
|
# contact info
|
|
871
1040
|
# self contact
|
|
@@ -957,6 +1126,24 @@ def VBD_solve_trimesh_no_self_contact(
|
|
|
957
1126
|
)
|
|
958
1127
|
# fmt: on
|
|
959
1128
|
|
|
1129
|
+
for i_adj_edge in range(get_vertex_num_adjacent_edges(adjacency, particle_index)):
|
|
1130
|
+
nei_edge_index, vertex_order_on_edge = get_vertex_adjacent_edge_id_order(adjacency, particle_index, i_adj_edge)
|
|
1131
|
+
f_edge, h_edge = evaluate_dihedral_angle_based_bending_force_hessian(
|
|
1132
|
+
nei_edge_index,
|
|
1133
|
+
vertex_order_on_edge,
|
|
1134
|
+
pos,
|
|
1135
|
+
prev_pos,
|
|
1136
|
+
edge_indices,
|
|
1137
|
+
edge_rest_angles,
|
|
1138
|
+
edge_rest_length,
|
|
1139
|
+
edge_bending_properties[nei_edge_index, 0],
|
|
1140
|
+
edge_bending_properties[nei_edge_index, 1],
|
|
1141
|
+
dt,
|
|
1142
|
+
)
|
|
1143
|
+
|
|
1144
|
+
f = f + f_edge
|
|
1145
|
+
h = h + h_edge
|
|
1146
|
+
|
|
960
1147
|
# body-particle contact
|
|
961
1148
|
particle_contact_count = min(body_particle_contact_count[particle_index], body_particle_contact_buffer_pre_alloc)
|
|
962
1149
|
|
|
@@ -1072,6 +1259,9 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
|
|
|
1072
1259
|
tri_materials: wp.array(dtype=float, ndim=2),
|
|
1073
1260
|
tri_areas: wp.array(dtype=float),
|
|
1074
1261
|
edge_indices: wp.array(dtype=wp.int32, ndim=2),
|
|
1262
|
+
edge_rest_angles: wp.array(dtype=float),
|
|
1263
|
+
edge_rest_length: wp.array(dtype=float),
|
|
1264
|
+
edge_bending_properties: wp.array(dtype=float, ndim=2),
|
|
1075
1265
|
adjacency: ForceElementAdjacencyInfo,
|
|
1076
1266
|
# contact info
|
|
1077
1267
|
# self contact
|
|
@@ -1239,6 +1429,15 @@ def VBD_solve_trimesh_with_self_contact_penetration_free(
|
|
|
1239
1429
|
for i_adj_edge in range(get_vertex_num_adjacent_edges(adjacency, particle_index)):
|
|
1240
1430
|
nei_edge_index, vertex_order_on_edge = get_vertex_adjacent_edge_id_order(adjacency, particle_index, i_adj_edge)
|
|
1241
1431
|
# vertex is on the edge; otherwise it only effects the bending energy n
|
|
1432
|
+
if edge_bending_properties[nei_edge_index, 0] != 0:
|
|
1433
|
+
f_edge, h_edge = evaluate_dihedral_angle_based_bending_force_hessian(
|
|
1434
|
+
nei_edge_index, vertex_order_on_edge, pos, pos_prev, edge_indices, edge_rest_angles, edge_rest_length,
|
|
1435
|
+
edge_bending_properties[nei_edge_index, 0], edge_bending_properties[nei_edge_index, 1], dt
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
f = f + f_edge
|
|
1439
|
+
h = h + h_edge
|
|
1440
|
+
|
|
1242
1441
|
if vertex_order_on_edge == 2 or vertex_order_on_edge == 3:
|
|
1243
1442
|
# collisions of neighbor triangles
|
|
1244
1443
|
if wp.static("contact_info" in VBD_DEBUG_PRINTING_OPTIONS):
|
|
@@ -1572,6 +1771,9 @@ class VBDIntegrator(Integrator):
|
|
|
1572
1771
|
self.model.tri_materials,
|
|
1573
1772
|
self.model.tri_areas,
|
|
1574
1773
|
self.model.edge_indices,
|
|
1774
|
+
self.model.edge_rest_angle,
|
|
1775
|
+
self.model.edge_rest_length,
|
|
1776
|
+
self.model.edge_bending_properties,
|
|
1575
1777
|
self.adjacency,
|
|
1576
1778
|
self.model.soft_contact_ke,
|
|
1577
1779
|
self.model.soft_contact_mu,
|
|
@@ -1659,6 +1861,9 @@ class VBDIntegrator(Integrator):
|
|
|
1659
1861
|
self.model.tri_materials,
|
|
1660
1862
|
self.model.tri_areas,
|
|
1661
1863
|
self.model.edge_indices,
|
|
1864
|
+
self.model.edge_rest_angle,
|
|
1865
|
+
self.model.edge_rest_length,
|
|
1866
|
+
self.model.edge_bending_properties,
|
|
1662
1867
|
self.adjacency,
|
|
1663
1868
|
# self-contact
|
|
1664
1869
|
self.trimesh_collision_detector.collision_info,
|
|
@@ -1783,7 +1988,7 @@ class VBDIntegrator(Integrator):
|
|
|
1783
1988
|
vertex_adjacent_edges[buffer_offset_v1 + fill_count_v1 * 2 + 1] = 3
|
|
1784
1989
|
vertex_adjacent_edges_fill_count[v1] = fill_count_v1 + 1
|
|
1785
1990
|
|
|
1786
|
-
o0 = edges_array[edge_id,
|
|
1991
|
+
o0 = edges_array[edge_id, 0]
|
|
1787
1992
|
if o0 != -1:
|
|
1788
1993
|
fill_count_o0 = vertex_adjacent_edges_fill_count[o0]
|
|
1789
1994
|
buffer_offset_o0 = vertex_adjacent_edges_offsets[o0]
|
|
@@ -1791,7 +1996,7 @@ class VBDIntegrator(Integrator):
|
|
|
1791
1996
|
vertex_adjacent_edges[buffer_offset_o0 + fill_count_o0 * 2 + 1] = 0
|
|
1792
1997
|
vertex_adjacent_edges_fill_count[o0] = fill_count_o0 + 1
|
|
1793
1998
|
|
|
1794
|
-
o1 = edges_array[edge_id,
|
|
1999
|
+
o1 = edges_array[edge_id, 1]
|
|
1795
2000
|
if o1 != -1:
|
|
1796
2001
|
fill_count_o1 = vertex_adjacent_edges_fill_count[o1]
|
|
1797
2002
|
buffer_offset_o1 = vertex_adjacent_edges_offsets[o1]
|
warp/sim/integrator_xpbd.py
CHANGED
|
@@ -595,7 +595,7 @@ def solve_tetrahedra(
|
|
|
595
595
|
x20 = x2 - x0
|
|
596
596
|
x30 = x3 - x0
|
|
597
597
|
|
|
598
|
-
Ds = wp.
|
|
598
|
+
Ds = wp.matrix_from_cols(x10, x20, x30)
|
|
599
599
|
Dm = rest_matrix[tid]
|
|
600
600
|
inv_QT = wp.transpose(Dm)
|
|
601
601
|
|
|
@@ -627,7 +627,7 @@ def solve_tetrahedra(
|
|
|
627
627
|
elif term == 1:
|
|
628
628
|
# volume conservation
|
|
629
629
|
C = wp.determinant(F) - 1.0
|
|
630
|
-
dC = wp.
|
|
630
|
+
dC = wp.matrix_from_cols(wp.cross(f2, f3), wp.cross(f3, f1), wp.cross(f1, f2))
|
|
631
631
|
compliance = volume_compliance
|
|
632
632
|
|
|
633
633
|
if C != 0.0:
|
|
@@ -691,7 +691,7 @@ def solve_tetrahedra(
|
|
|
691
691
|
# J = wp.determinant(F)
|
|
692
692
|
|
|
693
693
|
# C_vol = J - alpha
|
|
694
|
-
# # dCdx = wp.
|
|
694
|
+
# # dCdx = wp.matrix_from_cols(wp.cross(f2, f3), wp.cross(f3, f1), wp.cross(f1, f2))*wp.transpose(Dm)
|
|
695
695
|
|
|
696
696
|
# # grad1 = wp.vec3(dCdx[0,0], dCdx[1,0], dCdx[2,0])
|
|
697
697
|
# # grad2 = wp.vec3(dCdx[0,1], dCdx[1,1], dCdx[2,1])
|
|
@@ -766,7 +766,7 @@ def solve_tetrahedra2(
|
|
|
766
766
|
x20 = x2 - x0
|
|
767
767
|
x30 = x3 - x0
|
|
768
768
|
|
|
769
|
-
Ds = wp.
|
|
769
|
+
Ds = wp.matrix_from_cols(x10, x20, x30)
|
|
770
770
|
Dm = pose[tid]
|
|
771
771
|
|
|
772
772
|
inv_rest_volume = wp.determinant(Dm) * 6.0
|
|
@@ -837,7 +837,7 @@ def solve_tetrahedra2(
|
|
|
837
837
|
J = wp.determinant(F)
|
|
838
838
|
|
|
839
839
|
C_vol = J - alpha
|
|
840
|
-
# dCdx = wp.
|
|
840
|
+
# dCdx = wp.matrix_from_cols(wp.cross(f2, f3), wp.cross(f3, f1), wp.cross(f1, f2))*wp.transpose(Dm)
|
|
841
841
|
|
|
842
842
|
# grad1 = wp.vec3(dCdx[0,0], dCdx[1,0], dCdx[2,0])
|
|
843
843
|
# grad2 = wp.vec3(dCdx[0,1], dCdx[1,1], dCdx[2,1])
|
warp/sim/model.py
CHANGED
|
@@ -372,9 +372,14 @@ class Control:
|
|
|
372
372
|
should generally be created using the :func:`Model.control()` function.
|
|
373
373
|
"""
|
|
374
374
|
|
|
375
|
-
def __init__(self, model: Model):
|
|
376
|
-
|
|
377
|
-
|
|
375
|
+
def __init__(self, model: Model = None):
|
|
376
|
+
if model:
|
|
377
|
+
wp.utils.warn(
|
|
378
|
+
"Passing arguments to Control's __init__ is deprecated\n"
|
|
379
|
+
"and will be disallowed in a future version. Use Control() without arguments\ninstead.",
|
|
380
|
+
category=DeprecationWarning,
|
|
381
|
+
stacklevel=2,
|
|
382
|
+
)
|
|
378
383
|
|
|
379
384
|
self.joint_act: Optional[wp.array] = None
|
|
380
385
|
"""Array of joint control inputs with shape ``(joint_axis_count,)`` and type ``float``."""
|
|
@@ -388,17 +393,28 @@ class Control:
|
|
|
388
393
|
self.muscle_activations: Optional[wp.array] = None
|
|
389
394
|
"""Array of muscle activations with shape ``(muscle_count,)`` and type ``float``."""
|
|
390
395
|
|
|
391
|
-
def
|
|
392
|
-
"""Reset the control inputs to
|
|
396
|
+
def clear(self) -> None:
|
|
397
|
+
"""Reset the control inputs to zero."""
|
|
393
398
|
|
|
394
399
|
if self.joint_act is not None:
|
|
395
|
-
self.joint_act.
|
|
400
|
+
self.joint_act.zero_()
|
|
396
401
|
if self.tri_activations is not None:
|
|
397
|
-
self.tri_activations.
|
|
402
|
+
self.tri_activations.zero_()
|
|
398
403
|
if self.tet_activations is not None:
|
|
399
|
-
self.tet_activations.
|
|
404
|
+
self.tet_activations.zero_()
|
|
400
405
|
if self.muscle_activations is not None:
|
|
401
|
-
self.muscle_activations.
|
|
406
|
+
self.muscle_activations.zero_()
|
|
407
|
+
|
|
408
|
+
def reset(self) -> None:
|
|
409
|
+
"""Reset the control inputs to zero."""
|
|
410
|
+
|
|
411
|
+
wp.utils.warn(
|
|
412
|
+
"Control.reset() is deprecated and will be removed\nin a future version. Use Control.clear() instead.",
|
|
413
|
+
category=DeprecationWarning,
|
|
414
|
+
stacklevel=2,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
self.clear()
|
|
402
418
|
|
|
403
419
|
|
|
404
420
|
def compute_shape_mass(type, scale, src, density, is_solid, thickness):
|
|
@@ -543,6 +559,7 @@ class Model:
|
|
|
543
559
|
|
|
544
560
|
edge_indices (array): Bending edge indices, shape [edge_count*4], int, each row is [o0, o1, v1, v2], where v1, v2 are on the edge
|
|
545
561
|
edge_rest_angle (array): Bending edge rest angle, shape [edge_count], float
|
|
562
|
+
edge_rest_length (array): Bending edge rest length, shape [edge_count], float
|
|
546
563
|
edge_bending_properties (array): Bending edge stiffness and damping parameters, shape [edge_count, 2], float
|
|
547
564
|
|
|
548
565
|
tet_indices (array): Tetrahedral element indices, shape [tet_count*4], int
|
|
@@ -716,6 +733,7 @@ class Model:
|
|
|
716
733
|
|
|
717
734
|
self.edge_indices = None
|
|
718
735
|
self.edge_rest_angle = None
|
|
736
|
+
self.edge_rest_length = None
|
|
719
737
|
self.edge_bending_properties = None
|
|
720
738
|
self.edge_constraint_lambdas = None
|
|
721
739
|
|
|
@@ -878,7 +896,7 @@ class Model:
|
|
|
878
896
|
Returns:
|
|
879
897
|
Control: The control object
|
|
880
898
|
"""
|
|
881
|
-
c = Control(
|
|
899
|
+
c = Control()
|
|
882
900
|
if requires_grad is None:
|
|
883
901
|
requires_grad = self.requires_grad
|
|
884
902
|
if clone_variables:
|
|
@@ -1205,6 +1223,7 @@ class ModelBuilder:
|
|
|
1205
1223
|
# edges (bending)
|
|
1206
1224
|
self.edge_indices = []
|
|
1207
1225
|
self.edge_rest_angle = []
|
|
1226
|
+
self.edge_rest_length = []
|
|
1208
1227
|
self.edge_bending_properties = []
|
|
1209
1228
|
|
|
1210
1229
|
# tetrahedra
|
|
@@ -1384,7 +1403,11 @@ class ModelBuilder:
|
|
|
1384
1403
|
if builder.spring_count:
|
|
1385
1404
|
self.spring_indices.extend((np.array(builder.spring_indices, dtype=np.int32) + start_particle_idx).tolist())
|
|
1386
1405
|
if builder.edge_count:
|
|
1387
|
-
|
|
1406
|
+
# Update edge indices by adding offset, preserving -1 values
|
|
1407
|
+
edge_indices = np.array(builder.edge_indices, dtype=np.int32)
|
|
1408
|
+
mask = edge_indices != -1
|
|
1409
|
+
edge_indices[mask] += start_particle_idx
|
|
1410
|
+
self.edge_indices.extend(edge_indices.tolist())
|
|
1388
1411
|
if builder.tri_count:
|
|
1389
1412
|
self.tri_indices.extend((np.array(builder.tri_indices, dtype=np.int32) + start_particle_idx).tolist())
|
|
1390
1413
|
if builder.tet_count:
|
|
@@ -1518,6 +1541,7 @@ class ModelBuilder:
|
|
|
1518
1541
|
"particle_radius",
|
|
1519
1542
|
"particle_flags",
|
|
1520
1543
|
"edge_rest_angle",
|
|
1544
|
+
"edge_rest_length",
|
|
1521
1545
|
"edge_bending_properties",
|
|
1522
1546
|
"spring_rest_length",
|
|
1523
1547
|
"spring_stiffness",
|
|
@@ -3757,11 +3781,11 @@ class ModelBuilder:
|
|
|
3757
3781
|
edge_kd = edge_kd if edge_kd is not None else self.default_edge_kd
|
|
3758
3782
|
|
|
3759
3783
|
# compute rest angle
|
|
3784
|
+
x3 = self.particle_q[k]
|
|
3785
|
+
x4 = self.particle_q[l]
|
|
3760
3786
|
if rest is None:
|
|
3761
3787
|
x1 = self.particle_q[i]
|
|
3762
3788
|
x2 = self.particle_q[j]
|
|
3763
|
-
x3 = self.particle_q[k]
|
|
3764
|
-
x4 = self.particle_q[l]
|
|
3765
3789
|
|
|
3766
3790
|
n1 = wp.normalize(wp.cross(x3 - x1, x4 - x1))
|
|
3767
3791
|
n2 = wp.normalize(wp.cross(x4 - x2, x3 - x2))
|
|
@@ -3776,6 +3800,7 @@ class ModelBuilder:
|
|
|
3776
3800
|
|
|
3777
3801
|
self.edge_indices.append((i, j, k, l))
|
|
3778
3802
|
self.edge_rest_angle.append(rest)
|
|
3803
|
+
self.edge_rest_length.append(wp.length(x4 - x3))
|
|
3779
3804
|
self.edge_bending_properties.append((edge_ke, edge_kd))
|
|
3780
3805
|
|
|
3781
3806
|
def add_edges(
|
|
@@ -3807,6 +3832,8 @@ class ModelBuilder:
|
|
|
3807
3832
|
winding: (i, k, l), (j, l, k).
|
|
3808
3833
|
|
|
3809
3834
|
"""
|
|
3835
|
+
x3 = np.array(self.particle_q)[k]
|
|
3836
|
+
x4 = np.array(self.particle_q)[l]
|
|
3810
3837
|
if rest is None:
|
|
3811
3838
|
# compute rest angle
|
|
3812
3839
|
x1 = np.array(self.particle_q)[i]
|
|
@@ -3837,6 +3864,7 @@ class ModelBuilder:
|
|
|
3837
3864
|
|
|
3838
3865
|
self.edge_indices.extend(inds.tolist())
|
|
3839
3866
|
self.edge_rest_angle.extend(rest.tolist())
|
|
3867
|
+
self.edge_rest_length.extend(np.linalg.norm(x4 - x3, axis=1).tolist())
|
|
3840
3868
|
|
|
3841
3869
|
def init_if_none(arr, defaultValue):
|
|
3842
3870
|
if arr is None:
|
|
@@ -4628,6 +4656,7 @@ class ModelBuilder:
|
|
|
4628
4656
|
|
|
4629
4657
|
m.edge_indices = wp.array(self.edge_indices, dtype=wp.int32)
|
|
4630
4658
|
m.edge_rest_angle = wp.array(self.edge_rest_angle, dtype=wp.float32, requires_grad=requires_grad)
|
|
4659
|
+
m.edge_rest_length = wp.array(self.edge_rest_length, dtype=wp.float32, requires_grad=requires_grad)
|
|
4631
4660
|
m.edge_bending_properties = wp.array(
|
|
4632
4661
|
self.edge_bending_properties, dtype=wp.float32, requires_grad=requires_grad
|
|
4633
4662
|
)
|
warp/sim/utils.py
CHANGED
|
@@ -65,7 +65,7 @@ def quat_decompose(q: wp.quat):
|
|
|
65
65
|
Decompose a quaternion into a sequence of 3 rotations around x,y',z' respectively, i.e.: q = q_z''q_y'q_x.
|
|
66
66
|
"""
|
|
67
67
|
|
|
68
|
-
R = wp.
|
|
68
|
+
R = wp.matrix_from_cols(
|
|
69
69
|
wp.quat_rotate(q, wp.vec3(1.0, 0.0, 0.0)),
|
|
70
70
|
wp.quat_rotate(q, wp.vec3(0.0, 1.0, 0.0)),
|
|
71
71
|
wp.quat_rotate(q, wp.vec3(0.0, 0.0, 1.0)),
|
|
@@ -249,7 +249,7 @@ def transform_inertia(t: wp.transform, I: wp.spatial_matrix):
|
|
|
249
249
|
r2 = wp.quat_rotate(q, wp.vec3(0.0, 1.0, 0.0))
|
|
250
250
|
r3 = wp.quat_rotate(q, wp.vec3(0.0, 0.0, 1.0))
|
|
251
251
|
|
|
252
|
-
R = wp.
|
|
252
|
+
R = wp.matrix_from_cols(r1, r2, r3)
|
|
253
253
|
S = wp.mul(wp.skew(p), R)
|
|
254
254
|
|
|
255
255
|
T = wp.spatial_adjoint(R, S)
|