warp-lang 0.11.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.

Files changed (170) hide show
  1. warp/__init__.py +8 -0
  2. warp/bin/warp-clang.so +0 -0
  3. warp/bin/warp.so +0 -0
  4. warp/build.py +7 -6
  5. warp/build_dll.py +70 -79
  6. warp/builtins.py +10 -6
  7. warp/codegen.py +51 -19
  8. warp/config.py +7 -8
  9. warp/constants.py +3 -0
  10. warp/context.py +948 -245
  11. warp/dlpack.py +198 -113
  12. warp/examples/assets/bunny.usd +0 -0
  13. warp/examples/assets/cartpole.urdf +110 -0
  14. warp/examples/assets/crazyflie.usd +0 -0
  15. warp/examples/assets/cube.usda +42 -0
  16. warp/examples/assets/nv_ant.xml +92 -0
  17. warp/examples/assets/nv_humanoid.xml +183 -0
  18. warp/examples/assets/quadruped.urdf +268 -0
  19. warp/examples/assets/rocks.nvdb +0 -0
  20. warp/examples/assets/rocks.usd +0 -0
  21. warp/examples/assets/sphere.usda +56 -0
  22. warp/examples/assets/torus.usda +105 -0
  23. warp/examples/benchmarks/benchmark_api.py +383 -0
  24. warp/examples/benchmarks/benchmark_cloth.py +279 -0
  25. warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -0
  26. warp/examples/benchmarks/benchmark_cloth_jax.py +100 -0
  27. warp/examples/benchmarks/benchmark_cloth_numba.py +142 -0
  28. warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -0
  29. warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -0
  30. warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -0
  31. warp/examples/benchmarks/benchmark_cloth_warp.py +146 -0
  32. warp/examples/benchmarks/benchmark_launches.py +295 -0
  33. warp/examples/core/example_dem.py +221 -0
  34. warp/examples/core/example_fluid.py +267 -0
  35. warp/examples/core/example_graph_capture.py +129 -0
  36. warp/examples/core/example_marching_cubes.py +177 -0
  37. warp/examples/core/example_mesh.py +154 -0
  38. warp/examples/core/example_mesh_intersect.py +193 -0
  39. warp/examples/core/example_nvdb.py +169 -0
  40. warp/examples/core/example_raycast.py +89 -0
  41. warp/examples/core/example_raymarch.py +178 -0
  42. warp/examples/core/example_render_opengl.py +141 -0
  43. warp/examples/core/example_sph.py +389 -0
  44. warp/examples/core/example_torch.py +181 -0
  45. warp/examples/core/example_wave.py +249 -0
  46. warp/examples/fem/bsr_utils.py +380 -0
  47. warp/examples/fem/example_apic_fluid.py +391 -0
  48. warp/examples/fem/example_convection_diffusion.py +168 -0
  49. warp/examples/fem/example_convection_diffusion_dg.py +209 -0
  50. warp/examples/fem/example_convection_diffusion_dg0.py +194 -0
  51. warp/examples/fem/example_deformed_geometry.py +159 -0
  52. warp/examples/fem/example_diffusion.py +173 -0
  53. warp/examples/fem/example_diffusion_3d.py +152 -0
  54. warp/examples/fem/example_diffusion_mgpu.py +214 -0
  55. warp/examples/fem/example_mixed_elasticity.py +222 -0
  56. warp/examples/fem/example_navier_stokes.py +243 -0
  57. warp/examples/fem/example_stokes.py +192 -0
  58. warp/examples/fem/example_stokes_transfer.py +249 -0
  59. warp/examples/fem/mesh_utils.py +109 -0
  60. warp/examples/fem/plot_utils.py +287 -0
  61. warp/examples/optim/example_bounce.py +248 -0
  62. warp/examples/optim/example_cloth_throw.py +210 -0
  63. warp/examples/optim/example_diffray.py +535 -0
  64. warp/examples/optim/example_drone.py +850 -0
  65. warp/examples/optim/example_inverse_kinematics.py +169 -0
  66. warp/examples/optim/example_inverse_kinematics_torch.py +170 -0
  67. warp/examples/optim/example_spring_cage.py +234 -0
  68. warp/examples/optim/example_trajectory.py +201 -0
  69. warp/examples/sim/example_cartpole.py +128 -0
  70. warp/examples/sim/example_cloth.py +184 -0
  71. warp/examples/sim/example_granular.py +113 -0
  72. warp/examples/sim/example_granular_collision_sdf.py +185 -0
  73. warp/examples/sim/example_jacobian_ik.py +213 -0
  74. warp/examples/sim/example_particle_chain.py +106 -0
  75. warp/examples/sim/example_quadruped.py +179 -0
  76. warp/examples/sim/example_rigid_chain.py +191 -0
  77. warp/examples/sim/example_rigid_contact.py +176 -0
  78. warp/examples/sim/example_rigid_force.py +126 -0
  79. warp/examples/sim/example_rigid_gyroscopic.py +97 -0
  80. warp/examples/sim/example_rigid_soft_contact.py +124 -0
  81. warp/examples/sim/example_soft_body.py +178 -0
  82. warp/fabric.py +29 -20
  83. warp/fem/cache.py +0 -1
  84. warp/fem/dirichlet.py +0 -2
  85. warp/fem/integrate.py +0 -1
  86. warp/jax.py +45 -0
  87. warp/jax_experimental.py +339 -0
  88. warp/native/builtin.h +12 -0
  89. warp/native/bvh.cu +18 -18
  90. warp/native/clang/clang.cpp +8 -3
  91. warp/native/cuda_util.cpp +94 -5
  92. warp/native/cuda_util.h +35 -6
  93. warp/native/cutlass_gemm.cpp +1 -1
  94. warp/native/cutlass_gemm.cu +4 -1
  95. warp/native/error.cpp +66 -0
  96. warp/native/error.h +27 -0
  97. warp/native/mesh.cu +2 -2
  98. warp/native/reduce.cu +4 -4
  99. warp/native/runlength_encode.cu +2 -2
  100. warp/native/scan.cu +2 -2
  101. warp/native/sparse.cu +0 -1
  102. warp/native/temp_buffer.h +2 -2
  103. warp/native/warp.cpp +95 -60
  104. warp/native/warp.cu +1053 -218
  105. warp/native/warp.h +49 -32
  106. warp/optim/linear.py +33 -16
  107. warp/render/render_opengl.py +202 -101
  108. warp/render/render_usd.py +82 -40
  109. warp/sim/__init__.py +13 -4
  110. warp/sim/articulation.py +4 -5
  111. warp/sim/collide.py +320 -175
  112. warp/sim/import_mjcf.py +25 -30
  113. warp/sim/import_urdf.py +94 -63
  114. warp/sim/import_usd.py +51 -36
  115. warp/sim/inertia.py +3 -2
  116. warp/sim/integrator.py +233 -0
  117. warp/sim/integrator_euler.py +447 -469
  118. warp/sim/integrator_featherstone.py +1991 -0
  119. warp/sim/integrator_xpbd.py +1420 -640
  120. warp/sim/model.py +765 -487
  121. warp/sim/particles.py +2 -1
  122. warp/sim/render.py +35 -13
  123. warp/sim/utils.py +222 -11
  124. warp/stubs.py +8 -0
  125. warp/tape.py +16 -1
  126. warp/tests/aux_test_grad_customs.py +23 -0
  127. warp/tests/test_array.py +190 -1
  128. warp/tests/test_async.py +656 -0
  129. warp/tests/test_bool.py +50 -0
  130. warp/tests/test_dlpack.py +164 -11
  131. warp/tests/test_examples.py +166 -74
  132. warp/tests/test_fem.py +8 -1
  133. warp/tests/test_generics.py +15 -5
  134. warp/tests/test_grad.py +1 -1
  135. warp/tests/test_grad_customs.py +172 -12
  136. warp/tests/test_jax.py +254 -0
  137. warp/tests/test_large.py +29 -6
  138. warp/tests/test_launch.py +25 -0
  139. warp/tests/test_linear_solvers.py +20 -3
  140. warp/tests/test_matmul.py +61 -16
  141. warp/tests/test_matmul_lite.py +13 -13
  142. warp/tests/test_mempool.py +186 -0
  143. warp/tests/test_multigpu.py +3 -0
  144. warp/tests/test_options.py +16 -2
  145. warp/tests/test_peer.py +137 -0
  146. warp/tests/test_print.py +3 -1
  147. warp/tests/test_quat.py +23 -0
  148. warp/tests/test_sim_kinematics.py +97 -0
  149. warp/tests/test_snippet.py +126 -3
  150. warp/tests/test_streams.py +108 -79
  151. warp/tests/test_torch.py +16 -8
  152. warp/tests/test_utils.py +32 -27
  153. warp/tests/test_verify_fp.py +65 -0
  154. warp/tests/test_volume.py +1 -1
  155. warp/tests/unittest_serial.py +2 -0
  156. warp/tests/unittest_suites.py +12 -0
  157. warp/tests/unittest_utils.py +14 -7
  158. warp/thirdparty/unittest_parallel.py +15 -3
  159. warp/torch.py +10 -8
  160. warp/types.py +363 -246
  161. warp/utils.py +143 -19
  162. warp_lang-1.0.0.dist-info/LICENSE.md +126 -0
  163. warp_lang-1.0.0.dist-info/METADATA +394 -0
  164. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +167 -86
  165. warp/sim/optimizer.py +0 -138
  166. warp_lang-0.11.0.dist-info/LICENSE.md +0 -36
  167. warp_lang-0.11.0.dist-info/METADATA +0 -238
  168. /warp/tests/{walkthough_debug.py → walkthrough_debug.py} +0 -0
  169. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
  170. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/top_level.txt +0 -0
warp/sim/import_mjcf.py CHANGED
@@ -25,8 +25,10 @@ def parse_mjcf(
25
25
  contact_ke=1000.0,
26
26
  contact_kd=100.0,
27
27
  contact_kf=100.0,
28
+ contact_ka=0.0,
28
29
  contact_mu=0.5,
29
30
  contact_restitution=0.5,
31
+ contact_thickness=0.0,
30
32
  limit_ke=100.0,
31
33
  limit_kd=10.0,
32
34
  scale=1.0,
@@ -48,13 +50,15 @@ def parse_mjcf(
48
50
  density (float): The density of the shapes in kg/m^3 which will be used to calculate the body mass and inertia.
49
51
  stiffness (float): The stiffness of the joints.
50
52
  damping (float): The damping of the joints.
51
- contact_ke (float): The stiffness of the shape contacts (used by SemiImplicitIntegrator).
52
- contact_kd (float): The damping of the shape contacts (used by SemiImplicitIntegrator).
53
- contact_kf (float): The friction stiffness of the shape contacts (used by SemiImplicitIntegrator).
53
+ contact_ke (float): The stiffness of the shape contacts.
54
+ contact_kd (float): The damping of the shape contacts.
55
+ contact_kf (float): The friction stiffness of the shape contacts.
56
+ contact_ka (float): The adhesion distance of the shape contacts.
54
57
  contact_mu (float): The friction coefficient of the shape contacts.
55
58
  contact_restitution (float): The restitution coefficient of the shape contacts.
56
- limit_ke (float): The stiffness of the joint limits (used by SemiImplicitIntegrator).
57
- limit_kd (float): The damping of the joint limits (used by SemiImplicitIntegrator).
59
+ contact_thickness (float): The thickness to add to the shape geometry.
60
+ limit_ke (float): The stiffness of the joint limits.
61
+ limit_kd (float): The damping of the joint limits.
58
62
  scale (float): The scaling factor to apply to the imported mechanism.
59
63
  armature (float): Default joint armature to use if `armature` has not been defined for a joint in the MJCF.
60
64
  armature_scale (float): Scaling factor to apply to the MJCF-defined joint armature values.
@@ -73,6 +77,16 @@ def parse_mjcf(
73
77
  file = ET.parse(mjcf_filename)
74
78
  root = file.getroot()
75
79
 
80
+ contact_vars = dict(
81
+ ke=contact_ke,
82
+ kd=contact_kd,
83
+ kf=contact_kf,
84
+ ka=contact_ka,
85
+ mu=contact_mu,
86
+ restitution=contact_restitution,
87
+ thickness=contact_thickness,
88
+ )
89
+
76
90
  use_degrees = True # angles are in degrees by default
77
91
  euler_seq = [1, 2, 3] # XYZ by default
78
92
 
@@ -265,7 +279,7 @@ def parse_mjcf(
265
279
  joint_type = wp.sim.JOINT_FIXED
266
280
  break
267
281
  is_angular = joint_type_str == "hinge"
268
- mode = wp.sim.JOINT_MODE_LIMIT
282
+ mode = wp.sim.JOINT_MODE_FORCE
269
283
  if stiffness > 0.0 or "stiffness" in joint_attrib:
270
284
  mode = wp.sim.JOINT_MODE_TARGET_POSITION
271
285
  axis_vec = parse_vec(joint_attrib, "axis", (0.0, 0.0, 0.0))
@@ -355,11 +369,7 @@ def parse_mjcf(
355
369
  rot=geom_rot,
356
370
  radius=geom_size[0],
357
371
  density=geom_density,
358
- ke=contact_ke,
359
- kd=contact_kd,
360
- kf=contact_kf,
361
- mu=contact_mu,
362
- restitution=contact_restitution,
372
+ **contact_vars,
363
373
  )
364
374
 
365
375
  elif geom_type == "box":
@@ -371,11 +381,7 @@ def parse_mjcf(
371
381
  hy=geom_size[1],
372
382
  hz=geom_size[2],
373
383
  density=geom_density,
374
- ke=contact_ke,
375
- kd=contact_kd,
376
- kf=contact_kf,
377
- mu=contact_mu,
378
- restitution=contact_restitution,
384
+ **contact_vars,
379
385
  )
380
386
 
381
387
  elif geom_type == "mesh" and parse_meshes:
@@ -393,10 +399,7 @@ def parse_mjcf(
393
399
  mesh=mesh,
394
400
  scale=mesh_scale,
395
401
  density=density,
396
- ke=contact_ke,
397
- kd=contact_kd,
398
- kf=contact_kf,
399
- mu=contact_mu,
402
+ **contact_vars,
400
403
  )
401
404
 
402
405
  elif geom_type in {"capsule", "cylinder"}:
@@ -431,12 +434,8 @@ def parse_mjcf(
431
434
  radius=geom_radius,
432
435
  half_height=geom_height,
433
436
  density=density,
434
- ke=contact_ke,
435
- kd=contact_kd,
436
- kf=contact_kf,
437
- mu=contact_mu,
438
- restitution=contact_restitution,
439
437
  up_axis=geom_up_axis,
438
+ **contact_vars,
440
439
  )
441
440
  else:
442
441
  builder.add_shape_capsule(
@@ -446,12 +445,8 @@ def parse_mjcf(
446
445
  radius=geom_radius,
447
446
  half_height=geom_height,
448
447
  density=density,
449
- ke=contact_ke,
450
- kd=contact_kd,
451
- kf=contact_kf,
452
- mu=contact_mu,
453
- restitution=contact_restitution,
454
448
  up_axis=geom_up_axis,
449
+ **contact_vars,
455
450
  )
456
451
 
457
452
  else:
warp/sim/import_urdf.py CHANGED
@@ -14,6 +14,8 @@ import numpy as np
14
14
  import warp as wp
15
15
  from warp.sim.model import Mesh
16
16
 
17
+ from typing import Union
18
+
17
19
 
18
20
  def parse_urdf(
19
21
  urdf_filename,
@@ -25,16 +27,20 @@ def parse_urdf(
25
27
  stiffness=100.0,
26
28
  damping=10.0,
27
29
  armature=0.0,
28
- shape_ke=1.0e4,
29
- shape_kd=1.0e3,
30
- shape_kf=1.0e2,
31
- shape_mu=0.25,
32
- shape_restitution=0.5,
33
- shape_thickness=0.0,
30
+ contact_ke=1.0e4,
31
+ contact_kd=1.0e3,
32
+ contact_kf=1.0e2,
33
+ contact_ka=0.0,
34
+ contact_mu=0.25,
35
+ contact_restitution=0.5,
36
+ contact_thickness=0.0,
34
37
  limit_ke=100.0,
35
38
  limit_kd=10.0,
39
+ joint_limit_lower=-1e6,
40
+ joint_limit_upper=1e6,
36
41
  scale=1.0,
37
42
  parse_visuals_as_colliders=False,
43
+ force_show_colliders=False,
38
44
  enable_self_collisions=True,
39
45
  ignore_inertial_definitions=True,
40
46
  ensure_nonstatic_links=True,
@@ -54,16 +60,20 @@ def parse_urdf(
54
60
  stiffness (float): The stiffness of the joints.
55
61
  damping (float): The damping of the joints.
56
62
  armature (float): The armature of the joints (bias to add to the inertia diagonals that may stabilize the simulation).
57
- shape_ke (float): The stiffness of the shape contacts (used by SemiImplicitIntegrator).
58
- shape_kd (float): The damping of the shape contacts (used by SemiImplicitIntegrator).
59
- shape_kf (float): The friction stiffness of the shape contacts (used by SemiImplicitIntegrator).
60
- shape_mu (float): The friction coefficient of the shape contacts.
61
- shape_restitution (float): The restitution coefficient of the shape contacts.
62
- shape_thickness (float): The thickness to add to the shape geometry.
63
- limit_ke (float): The stiffness of the joint limits (used by SemiImplicitIntegrator).
64
- limit_kd (float): The damping of the joint limits (used by SemiImplicitIntegrator).
63
+ contact_ke (float): The stiffness of the shape contacts (used by the Euler integrators).
64
+ contact_kd (float): The damping of the shape contacts (used by the Euler integrators).
65
+ contact_kf (float): The friction stiffness of the shape contacts (used by the Euler integrators).
66
+ contact_ka (float): The adhesion distance of the shape contacts (used by the Euler integrators).
67
+ contact_mu (float): The friction coefficient of the shape contacts.
68
+ contact_restitution (float): The restitution coefficient of the shape contacts.
69
+ contact_thickness (float): The thickness to add to the shape geometry.
70
+ limit_ke (float): The stiffness of the joint limits (used by the Euler integrators).
71
+ limit_kd (float): The damping of the joint limits (used by the Euler integrators).
72
+ joint_limit_lower (float): The default lower joint limit if not specified in the URDF.
73
+ joint_limit_upper (float): The default upper joint limit if not specified in the URDF.
65
74
  scale (float): The scaling factor to apply to the imported mechanism.
66
- parse_visuals_as_colliders (bool): If True, the geometry defined under the `<visual>` tags is used for collision handling instead of the `<collision>` geometries.
75
+ parse_visuals_as_colliders (bool): If True, the geometry defined under the `<visual>` tags is used for collision handling instead of the `<collision>` geoemtries.
76
+ force_show_colliders (bool): If True, the collision shapes are always shown, even if there are visual shapes.
67
77
  enable_self_collisions (bool): If True, self-collisions are enabled.
68
78
  ignore_inertial_definitions (bool): If True, the inertial parameters defined in the URDF are ignored and the inertia is calculated from the shape geometry.
69
79
  ensure_nonstatic_links (bool): If True, links with zero mass are given a small mass (see `static_link_mass`) to ensure they are dynamic.
@@ -74,6 +84,16 @@ def parse_urdf(
74
84
  file = ET.parse(urdf_filename)
75
85
  root = file.getroot()
76
86
 
87
+ contact_vars = dict(
88
+ ke=contact_ke,
89
+ kd=contact_kd,
90
+ kf=contact_kf,
91
+ ka=contact_ka,
92
+ mu=contact_mu,
93
+ restitution=contact_restitution,
94
+ thickness=contact_thickness,
95
+ )
96
+
77
97
  def parse_transform(element):
78
98
  if element is None or element.find("origin") is None:
79
99
  return wp.transform()
@@ -84,21 +104,22 @@ def parse_urdf(
84
104
  rpy = [float(x) for x in rpy.split()]
85
105
  return wp.transform(xyz, wp.quat_rpy(*rpy))
86
106
 
87
- def parse_shapes(link, collisions, density, incoming_xform=None):
107
+ def parse_shapes(link, geoms, density, incoming_xform=None, visible=True, just_visual=False):
108
+ shapes = []
88
109
  # add geometry
89
- for collision in collisions:
90
- geo = collision.find("geometry")
110
+ for geom_group in geoms:
111
+ geo = geom_group.find("geometry")
91
112
  if geo is None:
92
113
  continue
93
114
 
94
- tf = parse_transform(collision)
115
+ tf = parse_transform(geom_group)
95
116
  if incoming_xform is not None:
96
117
  tf = incoming_xform * tf
97
118
 
98
119
  for box in geo.findall("box"):
99
120
  size = box.get("size") or "1 1 1"
100
121
  size = [float(x) for x in size.split()]
101
- builder.add_shape_box(
122
+ s = builder.add_shape_box(
102
123
  body=link,
103
124
  pos=wp.vec3(tf.p),
104
125
  rot=wp.quat(tf.q),
@@ -106,45 +127,39 @@ def parse_urdf(
106
127
  hy=size[1] * 0.5 * scale,
107
128
  hz=size[2] * 0.5 * scale,
108
129
  density=density,
109
- ke=shape_ke,
110
- kd=shape_kd,
111
- kf=shape_kf,
112
- mu=shape_mu,
113
- restitution=shape_restitution,
114
- thickness=shape_thickness,
130
+ is_visible=visible,
131
+ has_ground_collision=not just_visual,
132
+ **contact_vars,
115
133
  )
134
+ shapes.append(s)
116
135
 
117
136
  for sphere in geo.findall("sphere"):
118
- builder.add_shape_sphere(
137
+ s = builder.add_shape_sphere(
119
138
  body=link,
120
139
  pos=wp.vec3(tf.p),
121
140
  rot=wp.quat(tf.q),
122
141
  radius=float(sphere.get("radius") or "1") * scale,
123
142
  density=density,
124
- ke=shape_ke,
125
- kd=shape_kd,
126
- kf=shape_kf,
127
- mu=shape_mu,
128
- restitution=shape_restitution,
129
- thickness=shape_thickness,
143
+ is_visible=visible,
144
+ has_ground_collision=not just_visual,
145
+ **contact_vars,
130
146
  )
147
+ shapes.append(s)
131
148
 
132
149
  for cylinder in geo.findall("cylinder"):
133
- builder.add_shape_capsule(
150
+ s = builder.add_shape_capsule(
134
151
  body=link,
135
152
  pos=wp.vec3(tf.p),
136
153
  rot=wp.quat(tf.q),
137
154
  radius=float(cylinder.get("radius") or "1") * scale,
138
155
  half_height=float(cylinder.get("length") or "1") * 0.5 * scale,
139
156
  density=density,
140
- ke=shape_ke,
141
- kd=shape_kd,
142
- kf=shape_kf,
143
- mu=shape_mu,
144
157
  up_axis=2, # cylinders in URDF are aligned with z-axis
145
- restitution=shape_restitution,
146
- thickness=shape_thickness,
158
+ is_visible=visible,
159
+ has_ground_collision=not just_visual,
160
+ **contact_vars,
147
161
  )
162
+ shapes.append(s)
148
163
 
149
164
  for mesh in geo.findall("mesh"):
150
165
  filename = mesh.get("filename")
@@ -182,59 +197,70 @@ def parse_urdf(
182
197
  vertices = np.array(geom.vertices, dtype=np.float32) * scaling
183
198
  faces = np.array(geom.faces.flatten(), dtype=np.int32)
184
199
  mesh = Mesh(vertices, faces)
185
- builder.add_shape_mesh(
200
+ s = builder.add_shape_mesh(
186
201
  body=link,
187
202
  pos=wp.vec3(tf.p),
188
203
  rot=wp.quat(tf.q),
189
204
  mesh=mesh,
190
205
  density=density,
191
- ke=shape_ke,
192
- kd=shape_kd,
193
- kf=shape_kf,
194
- mu=shape_mu,
195
- restitution=shape_restitution,
196
- thickness=shape_thickness,
206
+ is_visible=visible,
207
+ has_ground_collision=not just_visual,
208
+ **contact_vars,
197
209
  )
210
+ shapes.append(s)
198
211
  else:
199
212
  # a single mesh
200
213
  vertices = np.array(m.vertices, dtype=np.float32) * scaling
201
214
  faces = np.array(m.faces.flatten(), dtype=np.int32)
202
215
  mesh = Mesh(vertices, faces)
203
- builder.add_shape_mesh(
216
+ s = builder.add_shape_mesh(
204
217
  body=link,
205
218
  pos=tf.p,
206
219
  rot=tf.q,
207
220
  mesh=mesh,
208
221
  density=density,
209
- ke=shape_ke,
210
- kd=shape_kd,
211
- kf=shape_kf,
212
- mu=shape_mu,
213
- restitution=shape_restitution,
214
- thickness=shape_thickness,
222
+ is_visible=visible,
223
+ has_ground_collision=not just_visual,
224
+ **contact_vars,
215
225
  )
226
+ shapes.append(s)
227
+
228
+ return shapes
216
229
 
217
230
  # maps from link name -> link index
218
231
  link_index = {}
219
232
 
233
+ visual_shapes = []
234
+
220
235
  builder.add_articulation()
221
236
 
222
237
  start_shape_count = len(builder.shape_geo_type)
223
238
 
224
239
  # add links
225
240
  for i, urdf_link in enumerate(root.findall("link")):
226
- if parse_visuals_as_colliders:
227
- colliders = urdf_link.findall("visual")
228
- else:
229
- colliders = urdf_link.findall("collision")
230
-
231
241
  name = urdf_link.get("name")
232
242
  link = builder.add_body(origin=wp.transform_identity(), armature=armature, name=name)
233
243
 
234
244
  # add ourselves to the index
235
245
  link_index[name] = link
236
246
 
237
- parse_shapes(link, colliders, density=density)
247
+ visuals = urdf_link.findall("visual")
248
+ colliders = urdf_link.findall("collision")
249
+
250
+ if parse_visuals_as_colliders:
251
+ colliders = visuals
252
+ else:
253
+ s = parse_shapes(link, visuals, density=0.0, just_visual=True)
254
+ visual_shapes.extend(s)
255
+
256
+ show_colliders = force_show_colliders
257
+ if parse_visuals_as_colliders:
258
+ show_colliders = True
259
+ elif len(visuals) == 0:
260
+ # we need to show the collision shapes since there are no visual shapes
261
+ show_colliders = True
262
+
263
+ parse_shapes(link, colliders, density=density, visible=show_colliders)
238
264
  m = builder.body_mass[link]
239
265
  if not ignore_inertial_definitions and urdf_link.find("inertial") is not None:
240
266
  # overwrite inertial parameters if defined
@@ -264,6 +290,7 @@ def parse_urdf(
264
290
  m = static_link_mass
265
291
  # cube with side length 0.5
266
292
  I_m = wp.mat33(np.eye(3)) * m / 12.0 * (0.5 * scale) ** 2 * 2.0
293
+ I_m += wp.mat33(armature * np.eye(3))
267
294
  builder.body_mass[link] = m
268
295
  builder.body_inv_mass[link] = 1.0 / m
269
296
  builder.body_inertia[link] = I_m
@@ -289,8 +316,8 @@ def parse_urdf(
289
316
  "origin": parse_transform(joint),
290
317
  "damping": damping,
291
318
  "friction": 0.0,
292
- "limit_lower": -1.0e6,
293
- "limit_upper": 1.0e6,
319
+ "limit_lower": joint_limit_lower,
320
+ "limit_upper": joint_limit_upper,
294
321
  }
295
322
  if joint.find("axis") is not None:
296
323
  joint_data["axis"] = joint.find("axis").get("xyz")
@@ -408,7 +435,7 @@ def parse_urdf(
408
435
  parent_xform = joint["origin"]
409
436
  child_xform = wp.transform_identity()
410
437
 
411
- joint_mode = wp.sim.JOINT_MODE_LIMIT
438
+ joint_mode = wp.sim.JOINT_MODE_FORCE
412
439
  if stiffness > 0.0:
413
440
  joint_mode = wp.sim.JOINT_MODE_TARGET_POSITION
414
441
 
@@ -476,6 +503,10 @@ def parse_urdf(
476
503
  else:
477
504
  raise Exception("Unsupported joint type: " + joint["type"])
478
505
 
506
+ for i in range(start_shape_count, end_shape_count):
507
+ for j in visual_shapes:
508
+ builder.shape_collision_filter_pairs.add((i, j))
509
+
479
510
  if not enable_self_collisions:
480
511
  for i in range(start_shape_count, end_shape_count):
481
512
  for j in range(i + 1, end_shape_count):
warp/sim/import_usd.py CHANGED
@@ -18,14 +18,16 @@ def parse_usd(
18
18
  default_density=1.0e3,
19
19
  only_load_enabled_rigid_bodies=False,
20
20
  only_load_enabled_joints=True,
21
- default_ke=1e5,
22
- default_kd=250.0,
23
- default_kf=500.0,
24
- default_mu=0.6,
25
- default_restitution=0.0,
26
- default_thickness=0.0,
21
+ contact_ke=1e5, # TODO rename to contact...
22
+ contact_kd=250.0,
23
+ contact_kf=500.0,
24
+ contact_ka=0.0,
25
+ contact_mu=0.6,
26
+ contact_restitution=0.0,
27
+ contact_thickness=0.0,
27
28
  joint_limit_ke=100.0,
28
29
  joint_limit_kd=10.0,
30
+ armature=0.0,
29
31
  invert_rotations=False,
30
32
  verbose=False,
31
33
  ignore_paths=[],
@@ -41,14 +43,16 @@ def parse_usd(
41
43
  default_density (float): The default density to use for bodies without a density attribute.
42
44
  only_load_enabled_rigid_bodies (bool): If True, only rigid bodies which do not have `physics:rigidBodyEnabled` set to False are loaded.
43
45
  only_load_enabled_joints (bool): If True, only joints which do not have `physics:jointEnabled` set to False are loaded.
44
- default_ke (float): The default contact stiffness to use, only considered by SemiImplicitIntegrator.
45
- default_kd (float): The default contact damping to use, only considered by SemiImplicitIntegrator.
46
- default_kf (float): The default friction stiffness to use, only considered by SemiImplicitIntegrator.
47
- default_mu (float): The default friction coefficient to use if a shape has not friction coefficient defined.
48
- default_restitution (float): The default coefficient of restitution to use if a shape has not coefficient of restitution defined.
49
- default_thickness (float): The thickness to add to the shape geometry.
50
- joint_limit_ke (float): The default stiffness to use for joint limits, only considered by SemiImplicitIntegrator.
51
- joint_limit_kd (float): The default damping to use for joint limits, only considered by SemiImplicitIntegrator.
46
+ contact_ke (float): The default contact stiffness to use, only considered by the Euler integrators.
47
+ contact_kd (float): The default contact damping to use, only considered by the Euler integrators.
48
+ contact_kf (float): The default friction stiffness to use, only considered by the Euler integrators.
49
+ contact_ka (float): The default adhesion distance to use, only considered by the Euler integrators.
50
+ contact_mu (float): The default friction coefficient to use if a shape has not friction coefficient defined.
51
+ contact_restitution (float): The default coefficient of restitution to use if a shape has not coefficient of restitution defined.
52
+ contact_thickness (float): The thickness to add to the shape geometry.
53
+ joint_limit_ke (float): The default stiffness to use for joint limits, only considered by the Euler integrators.
54
+ joint_limit_kd (float): The default damping to use for joint limits, only considered by the Euler integrators.
55
+ armature (float): The armature to use for the bodies.
52
56
  invert_rotations (bool): If True, inverts any rotations defined in the shape transforms.
53
57
  verbose (bool): If True, print additional information about the parsed USD file.
54
58
  ignore_paths (List[str]): A list of regular expressions matching prim paths to ignore.
@@ -150,14 +154,16 @@ def parse_usd(
150
154
  try:
151
155
  if UsdPhysics.StageHasAuthoredKilogramsPerUnit(stage):
152
156
  mass_unit = UsdPhysics.GetStageKilogramsPerUnit(stage)
153
- except:
154
- pass
157
+ except Exception as e:
158
+ if verbose:
159
+ print(f"Failed to get mass unit: {e}")
155
160
  linear_unit = 1.0
156
161
  try:
157
162
  if UsdGeom.StageHasAuthoredMetersPerUnit(stage):
158
163
  linear_unit = UsdGeom.GetStageMetersPerUnit(stage)
159
- except:
160
- pass
164
+ except Exception as e:
165
+ if verbose:
166
+ print(f"Failed to get linear unit: {e}")
161
167
 
162
168
  def parse_xform(prim):
163
169
  xform = UsdGeom.Xform(prim)
@@ -221,7 +227,8 @@ def parse_usd(
221
227
  high = joint_data["upperLimit"]
222
228
  else:
223
229
  high *= linear_unit
224
- mode = wp.sim.JOINT_MODE_LIMIT
230
+
231
+ mode = wp.sim.JOINT_MODE_FORCE
225
232
  if f"DriveAPI:{type}" in schemas_str:
226
233
  if target_vel is not None and target_vel != 0.0:
227
234
  mode = wp.sim.JOINT_MODE_TARGET_VELOCITY
@@ -234,7 +241,7 @@ def parse_usd(
234
241
  axis=(axis or joint_data["axis"]),
235
242
  limit_lower=low,
236
243
  limit_upper=high,
237
- target=(target_pos or target_vel or (low + high) / 2),
244
+ action=(target_pos or target_vel or (low + high) / 2),
238
245
  target_ke=stiffness,
239
246
  target_kd=damping,
240
247
  mode=mode,
@@ -249,8 +256,9 @@ def parse_usd(
249
256
  axis_str = "Y"
250
257
  try:
251
258
  axis_str = UsdGeom.GetStageUpAxis(stage)
252
- except:
253
- pass
259
+ except Exception as e:
260
+ if verbose:
261
+ print(f"Failed to parse stage up axis: {e}")
254
262
  upaxis = str2axis(axis_str)
255
263
 
256
264
  shape_types = {"Cube", "Sphere", "Mesh", "Capsule", "Plane", "Cylinder", "Cone"}
@@ -344,11 +352,11 @@ def parse_usd(
344
352
  if has_attribute(prim, "physics:density"):
345
353
  material["density"] = parse_float(prim, "physics:density") * mass_unit # / (linear_unit**3)
346
354
  if has_attribute(prim, "physics:restitution"):
347
- material["restitution"] = parse_float(prim, "physics:restitution", default_restitution)
355
+ material["restitution"] = parse_float(prim, "physics:restitution", contact_restitution)
348
356
  if has_attribute(prim, "physics:staticFriction"):
349
- material["staticFriction"] = parse_float(prim, "physics:staticFriction", default_mu)
357
+ material["staticFriction"] = parse_float(prim, "physics:staticFriction", contact_mu)
350
358
  if has_attribute(prim, "physics:dynamicFriction"):
351
- material["dynamicFriction"] = parse_float(prim, "physics:dynamicFriction", default_mu)
359
+ material["dynamicFriction"] = parse_float(prim, "physics:dynamicFriction", contact_mu)
352
360
  materials[path] = material
353
361
 
354
362
  elif type_name == "PhysicsScene":
@@ -364,8 +372,9 @@ def parse_usd(
364
372
  builder.up_vector = -builder.up_vector
365
373
  else:
366
374
  builder.up_vector = upaxis
367
- except:
368
- pass
375
+ except Exception as e:
376
+ if verbose:
377
+ print(f"Failed to parse physics scene: {e}")
369
378
 
370
379
  def parse_prim(prim, incoming_xform, incoming_scale, parent_body: int = -1):
371
380
  nonlocal builder
@@ -412,6 +421,7 @@ def parse_usd(
412
421
  body_id = builder.add_body(
413
422
  origin=xform,
414
423
  name=prim.GetName(),
424
+ armature=armature,
415
425
  )
416
426
  path_body_map[path] = body_id
417
427
  body_density[body_id] = 0.0
@@ -562,7 +572,12 @@ def parse_usd(
562
572
  elif type_name in shape_types:
563
573
  # parse shapes
564
574
  shape_params = dict(
565
- ke=default_ke, kd=default_kd, kf=default_kf, mu=default_mu, restitution=default_restitution
575
+ ke=contact_ke,
576
+ kd=contact_kd,
577
+ kf=contact_kf,
578
+ ka=contact_ka,
579
+ mu=contact_mu,
580
+ restitution=contact_restitution,
566
581
  )
567
582
  if material is not None:
568
583
  if "restitution" in material:
@@ -590,7 +605,7 @@ def parse_usd(
590
605
  hy=extents[1] / 2,
591
606
  hz=extents[2] / 2,
592
607
  density=density,
593
- thickness=default_thickness,
608
+ thickness=contact_thickness,
594
609
  **shape_params,
595
610
  )
596
611
  elif type_name == "Sphere":
@@ -626,7 +641,7 @@ def parse_usd(
626
641
  rot=geo_rot,
627
642
  width=width,
628
643
  length=length,
629
- thickness=default_thickness,
644
+ thickness=contact_thickness,
630
645
  **shape_params,
631
646
  )
632
647
  elif type_name == "Capsule":
@@ -699,7 +714,7 @@ def parse_usd(
699
714
  scale=scale,
700
715
  mesh=m,
701
716
  density=density,
702
- thickness=default_thickness,
717
+ thickness=contact_thickness,
703
718
  **shape_params,
704
719
  )
705
720
  else:
@@ -738,19 +753,19 @@ def parse_usd(
738
753
  builder.body_inv_mass[body_id] = 0.0
739
754
  # update inertia
740
755
  builder.body_inertia[body_id] *= mass_ratio
741
- if builder.body_inertia[body_id].any():
742
- builder.body_inv_inertia[body_id] = np.linalg.inv(builder.body_inertia[body_id])
756
+ if np.array(builder.body_inertia[body_id]).any():
757
+ builder.body_inv_inertia[body_id] = wp.inverse(builder.body_inertia[body_id])
743
758
  else:
744
- builder.body_inv_inertia[body_id] = np.zeros((3, 3), dtype=np.float32)
759
+ builder.body_inv_inertia[body_id] = wp.mat33(*np.zeros((3, 3), dtype=np.float32))
745
760
 
746
761
  if np.linalg.norm(i_diag) > 0.0:
747
762
  rot = np.array(wp.quat_to_matrix(i_rot), dtype=np.float32).reshape(3, 3)
748
763
  inertia = rot @ np.diag(i_diag) @ rot.T
749
764
  builder.body_inertia[body_id] = inertia
750
765
  if inertia.any():
751
- builder.body_inv_inertia[body_id] = np.linalg.inv(inertia)
766
+ builder.body_inv_inertia[body_id] = wp.inverse(wp.mat33(*inertia))
752
767
  else:
753
- builder.body_inv_inertia[body_id] = np.zeros((3, 3), dtype=np.float32)
768
+ builder.body_inv_inertia[body_id] = wp.mat33(*np.zeros((3, 3), dtype=np.float32))
754
769
 
755
770
  parse_prim(
756
771
  stage.GetDefaultPrim(), incoming_xform=wp.transform(), incoming_scale=np.ones(3, dtype=np.float32) * linear_unit
warp/sim/inertia.py CHANGED
@@ -33,7 +33,7 @@ def triangle_inertia(
33
33
 
34
34
  Dm = wp.mat33(pcom[0], qcom[0], rcom[0], pcom[1], qcom[1], rcom[1], pcom[2], qcom[2], rcom[2])
35
35
 
36
- volume = wp.determinant(Dm) / 6.0
36
+ volume = wp.abs(wp.determinant(Dm) / 6.0)
37
37
 
38
38
  # accumulate mass
39
39
  wp.atomic_add(mass, 0, 4.0 * density * volume)
@@ -260,6 +260,7 @@ def compute_mesh_inertia(
260
260
  """Computes mass, center of mass, 3x3 inertia matrix, and volume for a mesh."""
261
261
  com = wp.vec3(np.mean(vertices, 0))
262
262
 
263
+ indices = np.array(indices).flatten()
263
264
  num_tris = len(indices) // 3
264
265
 
265
266
  # compute signed inertia for each tetrahedron
@@ -305,7 +306,7 @@ def compute_mesh_inertia(
305
306
  # Extract mass and inertia and save to class attributes.
306
307
  mass = float(mass_warp.numpy()[0] * density)
307
308
  I = wp.mat33(*(I_warp.numpy()[0] * density))
308
- volume = vol_warp.numpy()[0]
309
+ volume = float(vol_warp.numpy()[0])
309
310
  return mass, com, I, volume
310
311
 
311
312