warp-lang 1.0.0b2__py3-none-win_amd64.whl → 1.0.0b6__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.

Files changed (271) hide show
  1. docs/conf.py +17 -5
  2. examples/env/env_ant.py +1 -1
  3. examples/env/env_cartpole.py +1 -1
  4. examples/env/env_humanoid.py +1 -1
  5. examples/env/env_usd.py +4 -1
  6. examples/env/environment.py +8 -9
  7. examples/example_dem.py +34 -33
  8. examples/example_diffray.py +364 -337
  9. examples/example_fluid.py +32 -23
  10. examples/example_jacobian_ik.py +97 -93
  11. examples/example_marching_cubes.py +6 -16
  12. examples/example_mesh.py +6 -16
  13. examples/example_mesh_intersect.py +16 -14
  14. examples/example_nvdb.py +14 -16
  15. examples/example_raycast.py +14 -13
  16. examples/example_raymarch.py +16 -23
  17. examples/example_render_opengl.py +19 -10
  18. examples/example_sim_cartpole.py +82 -78
  19. examples/example_sim_cloth.py +45 -48
  20. examples/example_sim_fk_grad.py +51 -44
  21. examples/example_sim_fk_grad_torch.py +47 -40
  22. examples/example_sim_grad_bounce.py +108 -133
  23. examples/example_sim_grad_cloth.py +99 -113
  24. examples/example_sim_granular.py +5 -6
  25. examples/{example_sim_sdf_shape.py → example_sim_granular_collision_sdf.py} +37 -26
  26. examples/example_sim_neo_hookean.py +51 -55
  27. examples/example_sim_particle_chain.py +4 -4
  28. examples/example_sim_quadruped.py +126 -81
  29. examples/example_sim_rigid_chain.py +54 -61
  30. examples/example_sim_rigid_contact.py +66 -70
  31. examples/example_sim_rigid_fem.py +3 -3
  32. examples/example_sim_rigid_force.py +1 -1
  33. examples/example_sim_rigid_gyroscopic.py +3 -4
  34. examples/example_sim_rigid_kinematics.py +28 -39
  35. examples/example_sim_trajopt.py +112 -110
  36. examples/example_sph.py +9 -8
  37. examples/example_wave.py +7 -7
  38. examples/fem/bsr_utils.py +30 -17
  39. examples/fem/example_apic_fluid.py +85 -69
  40. examples/fem/example_convection_diffusion.py +97 -93
  41. examples/fem/example_convection_diffusion_dg.py +142 -149
  42. examples/fem/example_convection_diffusion_dg0.py +141 -136
  43. examples/fem/example_deformed_geometry.py +146 -0
  44. examples/fem/example_diffusion.py +115 -84
  45. examples/fem/example_diffusion_3d.py +116 -86
  46. examples/fem/example_diffusion_mgpu.py +102 -79
  47. examples/fem/example_mixed_elasticity.py +139 -100
  48. examples/fem/example_navier_stokes.py +175 -162
  49. examples/fem/example_stokes.py +143 -111
  50. examples/fem/example_stokes_transfer.py +186 -157
  51. examples/fem/mesh_utils.py +59 -97
  52. examples/fem/plot_utils.py +138 -17
  53. tools/ci/publishing/build_nodes_info.py +54 -0
  54. warp/__init__.py +4 -3
  55. warp/__init__.pyi +1 -0
  56. warp/bin/warp-clang.dll +0 -0
  57. warp/bin/warp.dll +0 -0
  58. warp/build.py +5 -3
  59. warp/build_dll.py +29 -9
  60. warp/builtins.py +836 -492
  61. warp/codegen.py +864 -553
  62. warp/config.py +3 -1
  63. warp/context.py +389 -172
  64. warp/fem/__init__.py +24 -6
  65. warp/fem/cache.py +318 -25
  66. warp/fem/dirichlet.py +7 -3
  67. warp/fem/domain.py +14 -0
  68. warp/fem/field/__init__.py +30 -38
  69. warp/fem/field/field.py +149 -0
  70. warp/fem/field/nodal_field.py +244 -138
  71. warp/fem/field/restriction.py +8 -6
  72. warp/fem/field/test.py +127 -59
  73. warp/fem/field/trial.py +117 -60
  74. warp/fem/geometry/__init__.py +5 -1
  75. warp/fem/geometry/deformed_geometry.py +271 -0
  76. warp/fem/geometry/element.py +24 -1
  77. warp/fem/geometry/geometry.py +86 -14
  78. warp/fem/geometry/grid_2d.py +112 -54
  79. warp/fem/geometry/grid_3d.py +134 -65
  80. warp/fem/geometry/hexmesh.py +953 -0
  81. warp/fem/geometry/partition.py +85 -33
  82. warp/fem/geometry/quadmesh_2d.py +532 -0
  83. warp/fem/geometry/tetmesh.py +451 -115
  84. warp/fem/geometry/trimesh_2d.py +197 -92
  85. warp/fem/integrate.py +534 -268
  86. warp/fem/operator.py +58 -31
  87. warp/fem/polynomial.py +11 -0
  88. warp/fem/quadrature/__init__.py +1 -1
  89. warp/fem/quadrature/pic_quadrature.py +150 -58
  90. warp/fem/quadrature/quadrature.py +209 -57
  91. warp/fem/space/__init__.py +230 -53
  92. warp/fem/space/basis_space.py +489 -0
  93. warp/fem/space/collocated_function_space.py +105 -0
  94. warp/fem/space/dof_mapper.py +49 -2
  95. warp/fem/space/function_space.py +90 -39
  96. warp/fem/space/grid_2d_function_space.py +149 -496
  97. warp/fem/space/grid_3d_function_space.py +173 -538
  98. warp/fem/space/hexmesh_function_space.py +352 -0
  99. warp/fem/space/partition.py +129 -76
  100. warp/fem/space/quadmesh_2d_function_space.py +369 -0
  101. warp/fem/space/restriction.py +46 -34
  102. warp/fem/space/shape/__init__.py +15 -0
  103. warp/fem/space/shape/cube_shape_function.py +738 -0
  104. warp/fem/space/shape/shape_function.py +103 -0
  105. warp/fem/space/shape/square_shape_function.py +611 -0
  106. warp/fem/space/shape/tet_shape_function.py +567 -0
  107. warp/fem/space/shape/triangle_shape_function.py +429 -0
  108. warp/fem/space/tetmesh_function_space.py +132 -1039
  109. warp/fem/space/topology.py +295 -0
  110. warp/fem/space/trimesh_2d_function_space.py +104 -742
  111. warp/fem/types.py +13 -11
  112. warp/fem/utils.py +335 -60
  113. warp/native/array.h +120 -34
  114. warp/native/builtin.h +101 -72
  115. warp/native/bvh.cpp +73 -325
  116. warp/native/bvh.cu +406 -23
  117. warp/native/bvh.h +22 -40
  118. warp/native/clang/clang.cpp +1 -0
  119. warp/native/crt.h +2 -0
  120. warp/native/cuda_util.cpp +8 -3
  121. warp/native/cuda_util.h +1 -0
  122. warp/native/exports.h +1522 -1243
  123. warp/native/intersect.h +19 -4
  124. warp/native/intersect_adj.h +8 -8
  125. warp/native/mat.h +76 -17
  126. warp/native/mesh.cpp +33 -108
  127. warp/native/mesh.cu +114 -18
  128. warp/native/mesh.h +395 -40
  129. warp/native/noise.h +272 -329
  130. warp/native/quat.h +51 -8
  131. warp/native/rand.h +44 -34
  132. warp/native/reduce.cpp +1 -1
  133. warp/native/sparse.cpp +4 -4
  134. warp/native/sparse.cu +163 -155
  135. warp/native/spatial.h +2 -2
  136. warp/native/temp_buffer.h +18 -14
  137. warp/native/vec.h +103 -21
  138. warp/native/warp.cpp +2 -1
  139. warp/native/warp.cu +28 -3
  140. warp/native/warp.h +4 -3
  141. warp/render/render_opengl.py +261 -109
  142. warp/sim/__init__.py +1 -2
  143. warp/sim/articulation.py +385 -185
  144. warp/sim/import_mjcf.py +59 -48
  145. warp/sim/import_urdf.py +15 -15
  146. warp/sim/import_usd.py +174 -102
  147. warp/sim/inertia.py +17 -18
  148. warp/sim/integrator_xpbd.py +4 -3
  149. warp/sim/model.py +330 -250
  150. warp/sim/render.py +1 -1
  151. warp/sparse.py +625 -152
  152. warp/stubs.py +341 -309
  153. warp/tape.py +9 -6
  154. warp/tests/__main__.py +3 -6
  155. warp/tests/assets/curlnoise_golden.npy +0 -0
  156. warp/tests/assets/pnoise_golden.npy +0 -0
  157. warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
  158. warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
  159. warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
  160. warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
  161. warp/tests/aux_test_unresolved_func.py +14 -0
  162. warp/tests/aux_test_unresolved_symbol.py +14 -0
  163. warp/tests/disabled_kinematics.py +239 -0
  164. warp/tests/run_coverage_serial.py +31 -0
  165. warp/tests/test_adam.py +103 -106
  166. warp/tests/test_arithmetic.py +94 -74
  167. warp/tests/test_array.py +82 -101
  168. warp/tests/test_array_reduce.py +57 -23
  169. warp/tests/test_atomic.py +64 -28
  170. warp/tests/test_bool.py +22 -12
  171. warp/tests/test_builtins_resolution.py +1292 -0
  172. warp/tests/test_bvh.py +18 -18
  173. warp/tests/test_closest_point_edge_edge.py +54 -57
  174. warp/tests/test_codegen.py +165 -134
  175. warp/tests/test_compile_consts.py +28 -20
  176. warp/tests/test_conditional.py +108 -24
  177. warp/tests/test_copy.py +10 -12
  178. warp/tests/test_ctypes.py +112 -88
  179. warp/tests/test_dense.py +21 -14
  180. warp/tests/test_devices.py +98 -0
  181. warp/tests/test_dlpack.py +75 -75
  182. warp/tests/test_examples.py +237 -0
  183. warp/tests/test_fabricarray.py +22 -24
  184. warp/tests/test_fast_math.py +15 -11
  185. warp/tests/test_fem.py +1034 -124
  186. warp/tests/test_fp16.py +23 -16
  187. warp/tests/test_func.py +187 -86
  188. warp/tests/test_generics.py +194 -49
  189. warp/tests/test_grad.py +123 -181
  190. warp/tests/test_grad_customs.py +176 -0
  191. warp/tests/test_hash_grid.py +35 -34
  192. warp/tests/test_import.py +10 -23
  193. warp/tests/test_indexedarray.py +24 -25
  194. warp/tests/test_intersect.py +18 -9
  195. warp/tests/test_large.py +141 -0
  196. warp/tests/test_launch.py +14 -41
  197. warp/tests/test_lerp.py +64 -65
  198. warp/tests/test_lvalue.py +493 -0
  199. warp/tests/test_marching_cubes.py +12 -13
  200. warp/tests/test_mat.py +517 -2898
  201. warp/tests/test_mat_lite.py +115 -0
  202. warp/tests/test_mat_scalar_ops.py +2889 -0
  203. warp/tests/test_math.py +103 -9
  204. warp/tests/test_matmul.py +304 -69
  205. warp/tests/test_matmul_lite.py +410 -0
  206. warp/tests/test_mesh.py +60 -22
  207. warp/tests/test_mesh_query_aabb.py +21 -25
  208. warp/tests/test_mesh_query_point.py +111 -22
  209. warp/tests/test_mesh_query_ray.py +12 -24
  210. warp/tests/test_mlp.py +30 -22
  211. warp/tests/test_model.py +92 -89
  212. warp/tests/test_modules_lite.py +39 -0
  213. warp/tests/test_multigpu.py +88 -114
  214. warp/tests/test_noise.py +12 -11
  215. warp/tests/test_operators.py +16 -20
  216. warp/tests/test_options.py +11 -11
  217. warp/tests/test_pinned.py +17 -18
  218. warp/tests/test_print.py +32 -11
  219. warp/tests/test_quat.py +275 -129
  220. warp/tests/test_rand.py +18 -16
  221. warp/tests/test_reload.py +38 -34
  222. warp/tests/test_rounding.py +50 -43
  223. warp/tests/test_runlength_encode.py +168 -20
  224. warp/tests/test_smoothstep.py +9 -11
  225. warp/tests/test_snippet.py +143 -0
  226. warp/tests/test_sparse.py +261 -63
  227. warp/tests/test_spatial.py +276 -243
  228. warp/tests/test_streams.py +110 -85
  229. warp/tests/test_struct.py +268 -63
  230. warp/tests/test_tape.py +39 -21
  231. warp/tests/test_torch.py +90 -86
  232. warp/tests/test_transient_module.py +10 -12
  233. warp/tests/test_types.py +363 -0
  234. warp/tests/test_utils.py +451 -0
  235. warp/tests/test_vec.py +354 -2050
  236. warp/tests/test_vec_lite.py +73 -0
  237. warp/tests/test_vec_scalar_ops.py +2099 -0
  238. warp/tests/test_volume.py +418 -376
  239. warp/tests/test_volume_write.py +124 -134
  240. warp/tests/unittest_serial.py +35 -0
  241. warp/tests/unittest_suites.py +291 -0
  242. warp/tests/unittest_utils.py +342 -0
  243. warp/tests/{test_misc.py → unused_test_misc.py} +13 -5
  244. warp/tests/{test_debug.py → walkthough_debug.py} +3 -17
  245. warp/thirdparty/appdirs.py +36 -45
  246. warp/thirdparty/unittest_parallel.py +589 -0
  247. warp/types.py +622 -211
  248. warp/utils.py +54 -393
  249. warp_lang-1.0.0b6.dist-info/METADATA +238 -0
  250. warp_lang-1.0.0b6.dist-info/RECORD +409 -0
  251. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/WHEEL +1 -1
  252. examples/example_cache_management.py +0 -40
  253. examples/example_multigpu.py +0 -54
  254. examples/example_struct.py +0 -65
  255. examples/fem/example_stokes_transfer_3d.py +0 -210
  256. warp/bin/warp-clang.so +0 -0
  257. warp/bin/warp.so +0 -0
  258. warp/fem/field/discrete_field.py +0 -80
  259. warp/fem/space/nodal_function_space.py +0 -233
  260. warp/tests/test_all.py +0 -223
  261. warp/tests/test_array_scan.py +0 -60
  262. warp/tests/test_base.py +0 -208
  263. warp/tests/test_unresolved_func.py +0 -7
  264. warp/tests/test_unresolved_symbol.py +0 -7
  265. warp_lang-1.0.0b2.dist-info/METADATA +0 -26
  266. warp_lang-1.0.0b2.dist-info/RECORD +0 -380
  267. /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
  268. /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
  269. /warp/tests/{test_square.py → aux_test_square.py} +0 -0
  270. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/LICENSE.md +0 -0
  271. {warp_lang-1.0.0b2.dist-info → warp_lang-1.0.0b6.dist-info}/top_level.txt +0 -0
warp/sim/model.py CHANGED
@@ -99,11 +99,11 @@ class JointAxis:
99
99
 
100
100
  Attributes:
101
101
 
102
- axis (3D vector): The axis that this JointAxis object describes
102
+ axis (3D vector or JointAxis): The 3D axis that this JointAxis object describes, or alternatively another JointAxis object to copy from
103
103
  limit_lower (float): The lower limit of the joint axis
104
104
  limit_upper (float): The upper limit of the joint axis
105
- limit_ke (float): The elastic stiffness of the joint axis limits, only respected by SemiImplicitIntegrator
106
- limit_kd (float): The damping stiffness of the joint axis limits, only respected by SemiImplicitIntegrator
105
+ limit_ke (float): The elastic stiffness of the joint axis limits, only respected by :class:`SemiImplicitIntegrator`
106
+ limit_kd (float): The damping stiffness of the joint axis limits, only respected by :class:`SemiImplicitIntegrator`
107
107
  target (float): The target position or velocity (depending on the mode, see `Joint modes`_) of the joint axis
108
108
  target_ke (float): The proportional gain of the joint axis target drive PD controller
109
109
  target_kd (float): The derivative gain of the joint axis target drive PD controller
@@ -113,8 +113,8 @@ class JointAxis:
113
113
  def __init__(
114
114
  self,
115
115
  axis,
116
- limit_lower=-np.inf,
117
- limit_upper=np.inf,
116
+ limit_lower=-math.inf,
117
+ limit_upper=math.inf,
118
118
  limit_ke=100.0,
119
119
  limit_kd=10.0,
120
120
  target=None,
@@ -122,38 +122,52 @@ class JointAxis:
122
122
  target_kd=0.0,
123
123
  mode=JOINT_MODE_TARGET_POSITION,
124
124
  ):
125
- self.axis = np.array(wp.normalize(np.array(axis, dtype=np.float32)))
126
- self.limit_lower = limit_lower
127
- self.limit_upper = limit_upper
128
- self.limit_ke = limit_ke
129
- self.limit_kd = limit_kd
130
- if target is not None:
131
- self.target = target
132
- elif limit_lower > 0.0 or limit_upper < 0.0:
133
- self.target = 0.5 * (limit_lower + limit_upper)
125
+ if isinstance(axis, JointAxis):
126
+ self.axis = axis.axis
127
+ self.limit_lower = axis.limit_lower
128
+ self.limit_upper = axis.limit_upper
129
+ self.limit_ke = axis.limit_ke
130
+ self.limit_kd = axis.limit_kd
131
+ self.target = axis.target
132
+ self.target_ke = axis.target_ke
133
+ self.target_kd = axis.target_kd
134
+ self.mode = axis.mode
134
135
  else:
135
- self.target = 0.0
136
- self.target_ke = target_ke
137
- self.target_kd = target_kd
138
- self.mode = mode
136
+ self.axis = wp.normalize(wp.vec3(axis))
137
+ self.limit_lower = limit_lower
138
+ self.limit_upper = limit_upper
139
+ self.limit_ke = limit_ke
140
+ self.limit_kd = limit_kd
141
+ if target is not None:
142
+ self.target = target
143
+ elif limit_lower > 0.0 or limit_upper < 0.0:
144
+ self.target = 0.5 * (limit_lower + limit_upper)
145
+ else:
146
+ self.target = 0.0
147
+ self.target_ke = target_ke
148
+ self.target_kd = target_kd
149
+ self.mode = mode
139
150
 
140
151
 
141
152
  class SDF:
142
- # Describes a signed distance field for simulation
143
- #
144
- # Attributes:
145
- #
146
- # Either a NanoVDB file name or a numpy array
147
- #
148
- def __init__(self, volume=None, I=np.eye(3, dtype=np.float32), mass=1.0, com=np.array((0.0, 0.0, 0.0))):
153
+ """Describes a signed distance field for simulation
154
+
155
+ Attributes:
156
+
157
+ volume (Volume): The volume defining the SDF
158
+ I (Mat33): 3x3 inertia matrix of the SDF
159
+ mass (float): The total mass of the SDF
160
+ com (Vec3): The center of mass of the SDF
161
+ """
162
+ def __init__(self, volume=None, I=wp.mat33(np.eye(3)), mass=1.0, com=wp.vec3()):
149
163
  self.volume = volume
164
+ self.I = I
165
+ self.mass = mass
166
+ self.com = com
150
167
 
151
168
  # Need to specify these for now
152
169
  self.has_inertia = True
153
170
  self.is_solid = True
154
- self.mass = mass
155
- self.com = com
156
- self.I = I
157
171
 
158
172
  def finalize(self, device=None):
159
173
  return self.volume.id
@@ -164,12 +178,36 @@ class SDF:
164
178
 
165
179
  class Mesh:
166
180
  """Describes a triangle collision mesh for simulation
181
+
182
+ Example mesh creation from a triangle OBJ mesh file:
183
+ ====================================================
184
+
185
+ .. code-block:: python
186
+
187
+ import numpy as np
188
+ import warp as wp
189
+ import warp.sim
190
+
191
+ def load_mesh(self, filename, use_meshio=True):
192
+ if use_meshio:
193
+ import meshio
194
+ m = meshio.read(filename)
195
+ mesh_points = np.array(m.points)
196
+ mesh_indices = np.array(m.cells[0].data, dtype=np.int32).flatten()
197
+ else:
198
+ import openmesh
199
+ m = openmesh.read_trimesh(filename)
200
+ mesh_points = np.array(m.points())
201
+ mesh_indices = np.array(m.face_vertex_indices(), dtype=np.int32).flatten()
202
+ return wp.sim.Mesh(mesh_points, mesh_indices)
203
+
204
+ mesh = load_mesh("mesh.obj")
167
205
 
168
206
  Attributes:
169
207
 
170
- vertices (List[Vec3]): Mesh vertices
171
- indices (List[int]): Mesh indices
172
- I (Mat33): Inertia tensor of the mesh assuming density of 1.0 (around the center of mass)
208
+ vertices (List[Vec3]): Mesh 3D vertices points
209
+ indices (List[int]): Mesh indices as a flattened list of vertex indices describing triangles
210
+ I (Mat33): 3x3 inertia matrix of the mesh assuming density of 1.0 (around the center of mass)
173
211
  mass (float): The total mass of the body assuming density of 1.0
174
212
  com (Vec3): The center of mass of the body
175
213
  """
@@ -196,12 +234,20 @@ class Mesh:
196
234
  if compute_inertia:
197
235
  self.mass, self.com, self.I, _ = compute_mesh_inertia(1.0, vertices, indices, is_solid=is_solid)
198
236
  else:
199
- self.I = np.eye(3, dtype=np.float32)
237
+ self.I = wp.mat33(np.eye(3))
200
238
  self.mass = 1.0
201
- self.com = np.array((0.0, 0.0, 0.0))
239
+ self.com = wp.vec3()
202
240
 
203
- # construct simulation ready buffers from points
204
241
  def finalize(self, device=None):
242
+ """
243
+ Constructs a simulation-ready :class:`Mesh` object from the mesh data and returns its ID.
244
+
245
+ Args:
246
+ device: The device on which to allocate the mesh buffers
247
+
248
+ Returns:
249
+ The ID of the simulation-ready :class:`Mesh`
250
+ """
205
251
  with wp.ScopedDevice(device):
206
252
  pos = wp.array(self.vertices, dtype=wp.vec3)
207
253
  vel = wp.zeros_like(pos)
@@ -211,6 +257,9 @@ class Mesh:
211
257
  return self.mesh.id
212
258
 
213
259
  def __hash__(self):
260
+ """
261
+ Computes a hash of the mesh data for use in caching. The hash considers the mesh vertices, indices, and whether the mesh is solid or not.
262
+ """
214
263
  return hash((tuple(np.array(self.vertices).flatten()), tuple(np.array(self.indices).flatten()), self.is_solid))
215
264
 
216
265
 
@@ -228,13 +277,13 @@ class State:
228
277
  particle_count (int): Number of particles
229
278
  body_count (int): Number of rigid bodies
230
279
 
231
- particle_q (wp.array): Tensor of particle positions
232
- particle_qd (wp.array): Tensor of particle velocities
233
- particle_f (wp.array): Tensor of particle forces
280
+ particle_q (array): Tensor of particle positions
281
+ particle_qd (array): Tensor of particle velocities
282
+ particle_f (array): Tensor of particle forces
234
283
 
235
- body_q (wp.array): Tensor of body coordinates
236
- body_qd (wp.array): Tensor of body velocities
237
- body_f (wp.array): Tensor of body forces
284
+ body_q (array): Tensor of body coordinates
285
+ body_qd (array): Tensor of body velocities
286
+ body_f (array): Tensor of body forces
238
287
 
239
288
  """
240
289
 
@@ -276,7 +325,7 @@ class State:
276
325
 
277
326
  def compute_shape_mass(type, scale, src, density, is_solid, thickness):
278
327
  if density == 0.0 or type == GEO_PLANE: # zero density means fixed
279
- return 0.0, np.zeros(3), np.zeros((3, 3))
328
+ return 0.0, wp.vec3(), wp.mat33()
280
329
 
281
330
  if type == GEO_SPHERE:
282
331
  solid = compute_sphere_inertia(density, scale[0])
@@ -286,7 +335,7 @@ def compute_shape_mass(type, scale, src, density, is_solid, thickness):
286
335
  hollow = compute_sphere_inertia(density, scale[0] - thickness)
287
336
  return solid[0] - hollow[0], solid[1], solid[2] - hollow[2]
288
337
  elif type == GEO_BOX:
289
- w, h, d = np.array(scale[:3]) * 2.0
338
+ w, h, d = scale * 2.0
290
339
  solid = compute_box_inertia(density, w, h, d)
291
340
  if is_solid:
292
341
  return solid
@@ -321,13 +370,12 @@ def compute_shape_mass(type, scale, src, density, is_solid, thickness):
321
370
  if src.has_inertia and src.mass > 0.0 and src.is_solid == is_solid:
322
371
  m, c, I = src.mass, src.com, src.I
323
372
 
324
- s = np.array(scale[:3])
325
- sx, sy, sz = s
373
+ sx, sy, sz = scale
326
374
 
327
375
  mass_ratio = sx * sy * sz * density
328
376
  m_new = m * mass_ratio
329
377
 
330
- c_new = c * s
378
+ c_new = wp.cw_mul(c, scale)
331
379
 
332
380
  Ixx = I[0, 0] * (sy**2 + sz**2) / 2 * mass_ratio
333
381
  Iyy = I[1, 1] * (sx**2 + sz**2) / 2 * mass_ratio
@@ -336,12 +384,12 @@ def compute_shape_mass(type, scale, src, density, is_solid, thickness):
336
384
  Ixz = I[0, 2] * sx * sz * mass_ratio
337
385
  Iyz = I[1, 2] * sy * sz * mass_ratio
338
386
 
339
- I_new = np.array([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]])
387
+ I_new = wp.mat33([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]])
340
388
 
341
389
  return m_new, c_new, I_new
342
390
  elif type == GEO_MESH:
343
391
  # fall back to computing inertia from mesh geometry
344
- vertices = np.array(src.vertices) * np.array(scale[:3])
392
+ vertices = np.array(src.vertices) * np.array(scale)
345
393
  m, c, I, vol = compute_mesh_inertia(density, vertices, src.indices, is_solid, thickness)
346
394
  return m, c, I
347
395
  raise ValueError("Unsupported shape type: {}".format(type))
@@ -357,24 +405,24 @@ class Model:
357
405
  requires_grad (float): Indicates whether the model was finalized with gradient computation enabled
358
406
  num_envs (int): Number of articulation environments that were added to the ModelBuilder via `add_builder`
359
407
 
360
- particle_q (wp.array): Particle positions, shape [particle_count, 3], float
361
- particle_qd (wp.array): Particle velocities, shape [particle_count, 3], float
362
- particle_mass (wp.array): Particle mass, shape [particle_count], float
363
- particle_inv_mass (wp.array): Particle inverse mass, shape [particle_count], float
364
- particle_radius (wp.array): Particle radius, shape [particle_count], float
408
+ particle_q (array): Particle positions, shape [particle_count, 3], float
409
+ particle_qd (array): Particle velocities, shape [particle_count, 3], float
410
+ particle_mass (array): Particle mass, shape [particle_count], float
411
+ particle_inv_mass (array): Particle inverse mass, shape [particle_count], float
412
+ particle_radius (array): Particle radius, shape [particle_count], float
365
413
  particle_max_radius (float): Maximum particle radius (useful for HashGrid construction)
366
- particle_ke (wp.array): Particle normal contact stiffness (used by SemiImplicitIntegrator), shape [particle_count], float
367
- particle_kd (wp.array): Particle normal contact damping (used by SemiImplicitIntegrator), shape [particle_count], float
368
- particle_kf (wp.array): Particle friction force stiffness (used by SemiImplicitIntegrator), shape [particle_count], float
369
- particle_mu (wp.array): Particle friction coefficient, shape [particle_count], float
370
- particle_cohesion (wp.array): Particle cohesion strength, shape [particle_count], float
371
- particle_adhesion (wp.array): Particle adhesion strength, shape [particle_count], float
414
+ particle_ke (array): Particle normal contact stiffness (used by :class:`SemiImplicitIntegrator`), shape [particle_count], float
415
+ particle_kd (array): Particle normal contact damping (used by :class:`SemiImplicitIntegrator`), shape [particle_count], float
416
+ particle_kf (array): Particle friction force stiffness (used by :class:`SemiImplicitIntegrator`), shape [particle_count], float
417
+ particle_mu (array): Particle friction coefficient, shape [particle_count], float
418
+ particle_cohesion (array): Particle cohesion strength, shape [particle_count], float
419
+ particle_adhesion (array): Particle adhesion strength, shape [particle_count], float
372
420
  particle_grid (HashGrid): HashGrid instance used for accelerated simulation of particle interactions
373
- particle_flags (wp.array): Particle enabled state, shape [particle_count], bool
421
+ particle_flags (array): Particle enabled state, shape [particle_count], bool
374
422
  particle_max_velocity (float): Maximum particle velocity (to prevent instability)
375
423
 
376
- shape_transform (wp.array): Rigid shape transforms, shape [shape_count, 7], float
377
- shape_body (wp.array): Rigid shape body index, shape [shape_count], int
424
+ shape_transform (array): Rigid shape transforms, shape [shape_count, 7], float
425
+ shape_body (array): Rigid shape body index, shape [shape_count], int
378
426
  body_shapes (dict): Mapping from body index to list of attached shape indices
379
427
  shape_materials (ModelShapeMaterials): Rigid shape contact materials, shape [shape_count], float
380
428
  shape_shape_geo (ModelShapeGeometry): Shape geometry properties (geo type, scale, thickness, etc.), shape [shape_count, 3], float
@@ -383,68 +431,68 @@ class Model:
383
431
  shape_collision_group (list): Collision group of each shape, shape [shape_count], int
384
432
  shape_collision_group_map (dict): Mapping from collision group to list of shape indices
385
433
  shape_collision_filter_pairs (set): Pairs of shape indices that should not collide
386
- shape_collision_radius (wp.array): Collision radius of each shape used for bounding sphere broadphase collision checking, shape [shape_count], float
434
+ shape_collision_radius (array): Collision radius of each shape used for bounding sphere broadphase collision checking, shape [shape_count], float
387
435
  shape_ground_collision (list): Indicates whether each shape should collide with the ground, shape [shape_count], bool
388
- shape_contact_pairs (wp.array): Pairs of shape indices that may collide, shape [contact_pair_count, 2], int
389
- shape_ground_contact_pairs (wp.array): Pairs of shape, ground indices that may collide, shape [ground_contact_pair_count, 2], int
390
-
391
- spring_indices (wp.array): Particle spring indices, shape [spring_count*2], int
392
- spring_rest_length (wp.array): Particle spring rest length, shape [spring_count], float
393
- spring_stiffness (wp.array): Particle spring stiffness, shape [spring_count], float
394
- spring_damping (wp.array): Particle spring damping, shape [spring_count], float
395
- spring_control (wp.array): Particle spring activation, shape [spring_count], float
396
-
397
- tri_indices (wp.array): Triangle element indices, shape [tri_count*3], int
398
- tri_poses (wp.array): Triangle element rest pose, shape [tri_count, 2, 2], float
399
- tri_activations (wp.array): Triangle element activations, shape [tri_count], float
400
- tri_materials (wp.array): Triangle element materials, shape [tri_count, 5], float
401
-
402
- edge_indices (wp.array): Bending edge indices, shape [edge_count*4], int
403
- edge_rest_angle (wp.array): Bending edge rest angle, shape [edge_count], float
404
- edge_bending_properties (wp.array): Bending edge stiffness and damping parameters, shape [edge_count, 2], float
405
-
406
- tet_indices (wp.array): Tetrahedral element indices, shape [tet_count*4], int
407
- tet_poses (wp.array): Tetrahedral rest poses, shape [tet_count, 3, 3], float
408
- tet_activations (wp.array): Tetrahedral volumetric activations, shape [tet_count], float
409
- tet_materials (wp.array): Tetrahedral elastic parameters in form :math:`k_{mu}, k_{lambda}, k_{damp}`, shape [tet_count, 3]
410
-
411
- body_q (wp.array): Poses of rigid bodies used for state initialization, shape [body_count, 7], float
412
- body_qd (wp.array): Velocities of rigid bodies used for state initialization, shape [body_count, 6], float
413
- body_com (wp.array): Rigid body center of mass (in local frame), shape [body_count, 7], float
414
- body_inertia (wp.array): Rigid body inertia tensor (relative to COM), shape [body_count, 3, 3], float
415
- body_inv_inertia (wp.array): Rigid body inverse inertia tensor (relative to COM), shape [body_count, 3, 3], float
416
- body_mass (wp.array): Rigid body mass, shape [body_count], float
417
- body_inv_mass (wp.array): Rigid body inverse mass, shape [body_count], float
436
+ shape_contact_pairs (array): Pairs of shape indices that may collide, shape [contact_pair_count, 2], int
437
+ shape_ground_contact_pairs (array): Pairs of shape, ground indices that may collide, shape [ground_contact_pair_count, 2], int
438
+
439
+ spring_indices (array): Particle spring indices, shape [spring_count*2], int
440
+ spring_rest_length (array): Particle spring rest length, shape [spring_count], float
441
+ spring_stiffness (array): Particle spring stiffness, shape [spring_count], float
442
+ spring_damping (array): Particle spring damping, shape [spring_count], float
443
+ spring_control (array): Particle spring activation, shape [spring_count], float
444
+
445
+ tri_indices (array): Triangle element indices, shape [tri_count*3], int
446
+ tri_poses (array): Triangle element rest pose, shape [tri_count, 2, 2], float
447
+ tri_activations (array): Triangle element activations, shape [tri_count], float
448
+ tri_materials (array): Triangle element materials, shape [tri_count, 5], float
449
+
450
+ edge_indices (array): Bending edge indices, shape [edge_count*4], int
451
+ edge_rest_angle (array): Bending edge rest angle, shape [edge_count], float
452
+ edge_bending_properties (array): Bending edge stiffness and damping parameters, shape [edge_count, 2], float
453
+
454
+ tet_indices (array): Tetrahedral element indices, shape [tet_count*4], int
455
+ tet_poses (array): Tetrahedral rest poses, shape [tet_count, 3, 3], float
456
+ tet_activations (array): Tetrahedral volumetric activations, shape [tet_count], float
457
+ tet_materials (array): Tetrahedral elastic parameters in form :math:`k_{mu}, k_{lambda}, k_{damp}`, shape [tet_count, 3]
458
+
459
+ body_q (array): Poses of rigid bodies used for state initialization, shape [body_count, 7], float
460
+ body_qd (array): Velocities of rigid bodies used for state initialization, shape [body_count, 6], float
461
+ body_com (array): Rigid body center of mass (in local frame), shape [body_count, 7], float
462
+ body_inertia (array): Rigid body inertia tensor (relative to COM), shape [body_count, 3, 3], float
463
+ body_inv_inertia (array): Rigid body inverse inertia tensor (relative to COM), shape [body_count, 3, 3], float
464
+ body_mass (array): Rigid body mass, shape [body_count], float
465
+ body_inv_mass (array): Rigid body inverse mass, shape [body_count], float
418
466
  body_name (list): Rigid body names, shape [body_count], str
419
467
 
420
- joint_q (wp.array): Generalized joint positions used for state initialization, shape [joint_coord_count], float
421
- joint_qd (wp.array): Generalized joint velocities used for state initialization, shape [joint_dof_count], float
422
- joint_act (wp.array): Generalized joint actuation force, shape [joint_dof_count], float
423
- joint_type (wp.array): Joint type, shape [joint_count], int
424
- joint_parent (wp.array): Joint parent body indices, shape [joint_count], int
425
- joint_child (wp.array): Joint child body indices, shape [joint_count], int
426
- joint_X_p (wp.array): Joint transform in parent frame, shape [joint_count, 7], float
427
- joint_X_c (wp.array): Joint mass frame in child frame, shape [joint_count, 7], float
428
- joint_axis (wp.array): Joint axis in child frame, shape [joint_axis_count, 3], float
429
- joint_armature (wp.array): Armature for each joint, shape [joint_count], float
430
- joint_target (wp.array): Joint target position/velocity (depending on joint axis mode), shape [joint_axis_count], float
431
- joint_target_ke (wp.array): Joint stiffness, shape [joint_axis_count], float
432
- joint_target_kd (wp.array): Joint damping, shape [joint_axis_count], float
433
- joint_axis_start (wp.array): Start index of the first axis per joint, shape [joint_count], int
434
- joint_axis_dim (wp.array): Number of linear and angular axes per joint, shape [joint_count, 2], int
435
- joint_axis_mode (wp.array): Joint axis mode, shape [joint_axis_count], int
436
- joint_linear_compliance (wp.array): Joint linear compliance, shape [joint_count], float
437
- joint_angular_compliance (wp.array): Joint linear compliance, shape [joint_count], float
438
- joint_enabled (wp.array): Joint enabled, shape [joint_count], int
439
- joint_limit_lower (wp.array): Joint lower position limits, shape [joint_count], float
440
- joint_limit_upper (wp.array): Joint upper position limits, shape [joint_count], float
441
- joint_limit_ke (wp.array): Joint position limit stiffness (used by SemiImplicitIntegrator), shape [joint_count], float
442
- joint_limit_kd (wp.array): Joint position limit damping (used by SemiImplicitIntegrator), shape [joint_count], float
443
- joint_twist_lower (wp.array): Joint lower twist limit, shape [joint_count], float
444
- joint_twist_upper (wp.array): Joint upper twist limit, shape [joint_count], float
445
- joint_q_start (wp.array): Start index of the first position coordinate per joint, shape [joint_count], int
446
- joint_qd_start (wp.array): Start index of the first velocity coordinate per joint, shape [joint_count], int
447
- articulation_start (wp.array): Articulation start index, shape [articulation_count], int
468
+ joint_q (array): Generalized joint positions used for state initialization, shape [joint_coord_count], float
469
+ joint_qd (array): Generalized joint velocities used for state initialization, shape [joint_dof_count], float
470
+ joint_act (array): Generalized joint actuation force, shape [joint_dof_count], float
471
+ joint_type (array): Joint type, shape [joint_count], int
472
+ joint_parent (array): Joint parent body indices, shape [joint_count], int
473
+ joint_child (array): Joint child body indices, shape [joint_count], int
474
+ joint_X_p (array): Joint transform in parent frame, shape [joint_count, 7], float
475
+ joint_X_c (array): Joint mass frame in child frame, shape [joint_count, 7], float
476
+ joint_axis (array): Joint axis in child frame, shape [joint_axis_count, 3], float
477
+ joint_armature (array): Armature for each joint, shape [joint_count], float
478
+ joint_target (array): Joint target position/velocity (depending on joint axis mode), shape [joint_axis_count], float
479
+ joint_target_ke (array): Joint stiffness, shape [joint_axis_count], float
480
+ joint_target_kd (array): Joint damping, shape [joint_axis_count], float
481
+ joint_axis_start (array): Start index of the first axis per joint, shape [joint_count], int
482
+ joint_axis_dim (array): Number of linear and angular axes per joint, shape [joint_count, 2], int
483
+ joint_axis_mode (array): Joint axis mode, shape [joint_axis_count], int
484
+ joint_linear_compliance (array): Joint linear compliance, shape [joint_count], float
485
+ joint_angular_compliance (array): Joint linear compliance, shape [joint_count], float
486
+ joint_enabled (array): Joint enabled, shape [joint_count], int
487
+ joint_limit_lower (array): Joint lower position limits, shape [joint_count], float
488
+ joint_limit_upper (array): Joint upper position limits, shape [joint_count], float
489
+ joint_limit_ke (array): Joint position limit stiffness (used by SemiImplicitIntegrator), shape [joint_count], float
490
+ joint_limit_kd (array): Joint position limit damping (used by SemiImplicitIntegrator), shape [joint_count], float
491
+ joint_twist_lower (array): Joint lower twist limit, shape [joint_count], float
492
+ joint_twist_upper (array): Joint upper twist limit, shape [joint_count], float
493
+ joint_q_start (array): Start index of the first position coordinate per joint, shape [joint_count], int
494
+ joint_qd_start (array): Start index of the first velocity coordinate per joint, shape [joint_count], int
495
+ articulation_start (array): Articulation start index, shape [articulation_count], int
448
496
  joint_name (list): Joint names, shape [joint_count], str
449
497
  joint_attach_ke (float): Joint attachment force stiffness (used by SemiImplicitIntegrator)
450
498
  joint_attach_kd (float): Joint attachment force damping (used by SemiImplicitIntegrator)
@@ -461,7 +509,7 @@ class Model:
461
509
  rigid_contact_rolling_friction (float): Rolling friction coefficient for rigid body contacts (used by XPBDIntegrator)
462
510
 
463
511
  ground (bool): Whether the ground plane and ground contacts are enabled
464
- ground_plane (wp.array): Ground plane 3D normal and offset, shape [4], float
512
+ ground_plane (array): Ground plane 3D normal and offset, shape [4], float
465
513
  up_vector (np.ndarray): Up vector of the world, shape [3], float
466
514
  up_axis (int): Up axis, 0 for x, 1 for y, 2 for z
467
515
  gravity (np.ndarray): Gravity vector, shape [3], float
@@ -858,7 +906,7 @@ class Model:
858
906
 
859
907
  @property
860
908
  def particle_radius(self):
861
- """Array of per-particle radii"""
909
+ # Array of per-particle radii
862
910
  return self._particle_radius
863
911
 
864
912
  @particle_radius.setter
@@ -1082,8 +1130,8 @@ class ModelBuilder:
1082
1130
  self.joint_coord_count = 0
1083
1131
  self.joint_axis_total_count = 0
1084
1132
 
1085
- self.up_vector = np.array(up_vector)
1086
- self.up_axis = np.argmax(np.abs(up_vector))
1133
+ self.up_vector = wp.vec3(up_vector)
1134
+ self.up_axis = wp.vec3(np.argmax(np.abs(up_vector)))
1087
1135
  self.gravity = gravity
1088
1136
  # indicates whether a ground plane has been created
1089
1137
  self._ground_created = False
@@ -1174,10 +1222,10 @@ class ModelBuilder:
1174
1222
  """Copies a rigid articulation from `articulation`, another `ModelBuilder`.
1175
1223
 
1176
1224
  Args:
1177
- articulation: a model builder to add rigid articulation from.
1178
- xform: offset transform applied to root bodies.
1179
- update_num_env_count: if True, the number of environments is incremented by 1.
1180
- separate_collision_group: if True, the shapes from the articulation will all be put into a single new collision group, otherwise, only the shapes in collision group > -1 will be moved to a new group.
1225
+ articulation (ModelBuilder): a model builder to add rigid articulation from.
1226
+ xform (:ref:`transform <transform>`): offset transform applied to root bodies.
1227
+ update_num_env_count (bool): if True, the number of environments is incremented by 1.
1228
+ separate_collision_group (bool): if True, the shapes from the articulation will all be put into a single new collision group, otherwise, only the shapes in collision group > -1 will be moved to a new group.
1181
1229
  """
1182
1230
 
1183
1231
  start_body_idx = self.body_count
@@ -1317,8 +1365,8 @@ class ModelBuilder:
1317
1365
  self,
1318
1366
  origin: Transform = wp.transform(),
1319
1367
  armature: float = 0.0,
1320
- com: Vec3 = np.zeros(3),
1321
- I_m: Mat33 = np.zeros((3, 3)),
1368
+ com: Vec3 = wp.vec3(),
1369
+ I_m: Mat33 = wp.mat33(),
1322
1370
  m: float = 0.0,
1323
1371
  name: str = None,
1324
1372
  ) -> int:
@@ -1343,7 +1391,7 @@ class ModelBuilder:
1343
1391
  body_id = len(self.body_mass)
1344
1392
 
1345
1393
  # body data
1346
- inertia = I_m + np.eye(3) * armature
1394
+ inertia = I_m + wp.mat33(np.eye(3)) * armature
1347
1395
  self.body_inertia.append(inertia)
1348
1396
  self.body_mass.append(m)
1349
1397
  self.body_com.append(com)
@@ -1353,8 +1401,8 @@ class ModelBuilder:
1353
1401
  else:
1354
1402
  self.body_inv_mass.append(0.0)
1355
1403
 
1356
- if inertia.any():
1357
- self.body_inv_inertia.append(np.linalg.inv(inertia))
1404
+ if any(x for x in inertia):
1405
+ self.body_inv_inertia.append(wp.inverse(inertia))
1358
1406
  else:
1359
1407
  self.body_inv_inertia.append(inertia)
1360
1408
 
@@ -1390,16 +1438,19 @@ class ModelBuilder:
1390
1438
  linear_axes: The linear axes (see :class:`JointAxis`) of the joint
1391
1439
  angular_axes: The angular axes (see :class:`JointAxis`) of the joint
1392
1440
  name: The name of the joint
1393
- parent_xform: The transform of the joint in the parent body's local frame
1394
- child_xform: The transform of the joint in the child body's local frame
1441
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1442
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1395
1443
  linear_compliance: The linear compliance of the joint
1396
1444
  angular_compliance: The angular compliance of the joint
1397
1445
  collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
1398
1446
  enabled: Whether the joint is enabled
1399
1447
 
1400
1448
  Returns:
1401
- The index of the child body
1449
+ The index of the added joint
1402
1450
  """
1451
+ if len(self.articulation_start) == 0:
1452
+ # automatically add an articulation if none exists
1453
+ self.add_articulation()
1403
1454
  self.joint_type.append(joint_type)
1404
1455
  self.joint_parent.append(parent)
1405
1456
  if child not in self.joint_parents:
@@ -1407,8 +1458,8 @@ class ModelBuilder:
1407
1458
  else:
1408
1459
  self.joint_parents[child].append(parent)
1409
1460
  self.joint_child.append(child)
1410
- self.joint_X_p.append([*parent_xform])
1411
- self.joint_X_c.append([*child_xform])
1461
+ self.joint_X_p.append(wp.transform(parent_xform))
1462
+ self.joint_X_c.append(wp.transform(child_xform))
1412
1463
  self.joint_name.append(name or f"joint {self.joint_count}")
1413
1464
  self.joint_axis_start.append(len(self.joint_axis))
1414
1465
  self.joint_axis_dim.append((len(linear_axes), len(angular_axes)))
@@ -1451,7 +1502,7 @@ class ModelBuilder:
1451
1502
  elif joint_type == JOINT_BALL:
1452
1503
  dof_count = 3
1453
1504
  coord_count = 4
1454
- elif joint_type == JOINT_FREE:
1505
+ elif joint_type == JOINT_FREE or joint_type == JOINT_DISTANCE:
1455
1506
  dof_count = 6
1456
1507
  coord_count = 7
1457
1508
  elif joint_type == JOINT_FIXED:
@@ -1463,10 +1514,6 @@ class ModelBuilder:
1463
1514
  elif joint_type == JOINT_COMPOUND:
1464
1515
  dof_count = 3
1465
1516
  coord_count = 3
1466
- elif joint_type == JOINT_DISTANCE:
1467
- # todo use free joint dofs?
1468
- dof_count = 0
1469
- coord_count = 0
1470
1517
  elif joint_type == JOINT_D6:
1471
1518
  dof_count = len(linear_axes) + len(angular_axes)
1472
1519
  coord_count = dof_count
@@ -1478,7 +1525,7 @@ class ModelBuilder:
1478
1525
  self.joint_qd.append(0.0)
1479
1526
  self.joint_act.append(0.0)
1480
1527
 
1481
- if joint_type == JOINT_FREE or joint_type == JOINT_BALL:
1528
+ if joint_type == JOINT_FREE or joint_type == JOINT_DISTANCE or joint_type == JOINT_BALL:
1482
1529
  # ensure that a valid quaternion is used for the angular dofs
1483
1530
  self.joint_q[-1] = 1.0
1484
1531
 
@@ -1516,14 +1563,14 @@ class ModelBuilder:
1516
1563
  collision_filter_parent: bool = True,
1517
1564
  enabled: bool = True,
1518
1565
  ) -> int:
1519
- """Adds a revolute joint to the model
1566
+ """Adds a revolute (hinge) joint to the model. It has one degree of freedom.
1520
1567
 
1521
1568
  Args:
1522
1569
  parent: The index of the parent body
1523
1570
  child: The index of the child body
1524
- parent_xform: The transform of the joint in the parent body's local frame
1525
- child_xform: The transform of the joint in the child body's local frame
1526
- axis: The axis of rotation in the parent body's local frame
1571
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1572
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1573
+ axis (3D vector or JointAxis): The axis of rotation in the parent body's local frame, can be a JointAxis object whose settings will be used instead of the other arguments
1527
1574
  target: The target angle (in radians) of the joint
1528
1575
  target_ke: The stiffness of the joint target
1529
1576
  target_kd: The damping of the joint target
@@ -1538,7 +1585,7 @@ class ModelBuilder:
1538
1585
  enabled: Whether the joint is enabled
1539
1586
 
1540
1587
  Returns:
1541
- The index of the child body
1588
+ The index of the added joint
1542
1589
 
1543
1590
  """
1544
1591
  ax = JointAxis(
@@ -1587,14 +1634,14 @@ class ModelBuilder:
1587
1634
  collision_filter_parent: bool = True,
1588
1635
  enabled: bool = True,
1589
1636
  ) -> int:
1590
- """Adds a prismatic joint to the model
1637
+ """Adds a prismatic (sliding) joint to the model. It has one degree of freedom.
1591
1638
 
1592
1639
  Args:
1593
1640
  parent: The index of the parent body
1594
1641
  child: The index of the child body
1595
- parent_xform: The transform of the joint in the parent body's local frame
1596
- child_xform: The transform of the joint in the child body's local frame
1597
- axis: The axis of rotation in the parent body's local frame
1642
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1643
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1644
+ axis (3D vector or JointAxis): The axis of rotation in the parent body's local frame, can be a JointAxis object whose settings will be used instead of the other arguments
1598
1645
  target: The target position of the joint
1599
1646
  target_ke: The stiffness of the joint target
1600
1647
  target_kd: The damping of the joint target
@@ -1609,7 +1656,7 @@ class ModelBuilder:
1609
1656
  enabled: Whether the joint is enabled
1610
1657
 
1611
1658
  Returns:
1612
- The index of the child body
1659
+ The index of the added joint
1613
1660
 
1614
1661
  """
1615
1662
  ax = JointAxis(
@@ -1649,13 +1696,13 @@ class ModelBuilder:
1649
1696
  collision_filter_parent: bool = True,
1650
1697
  enabled: bool = True,
1651
1698
  ) -> int:
1652
- """Adds a ball joint to the model
1699
+ """Adds a ball (spherical) joint to the model. Its position is defined by a 4D quaternion (xyzw) and its velocity is a 3D vector.
1653
1700
 
1654
1701
  Args:
1655
1702
  parent: The index of the parent body
1656
1703
  child: The index of the child body
1657
- parent_xform: The transform of the joint in the parent body's local frame
1658
- xform: The transform of the joint in the child body's local frame
1704
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1705
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1659
1706
  linear_compliance: The linear compliance of the joint
1660
1707
  angular_compliance: The angular compliance of the joint
1661
1708
  name: The name of the joint
@@ -1663,7 +1710,7 @@ class ModelBuilder:
1663
1710
  enabled: Whether the joint is enabled
1664
1711
 
1665
1712
  Returns:
1666
- The index of the child body
1713
+ The index of the added joint
1667
1714
 
1668
1715
  """
1669
1716
  return self.add_joint(
@@ -1691,13 +1738,14 @@ class ModelBuilder:
1691
1738
  collision_filter_parent: bool = True,
1692
1739
  enabled: bool = True,
1693
1740
  ) -> int:
1694
- """Adds a fixed joint to the model
1741
+ """Adds a fixed (static) joint to the model. It has no degrees of freedom.
1742
+ See :meth:`collapse_fixed_joints` for a helper function that removes these fixed joints and merges the connecting bodies to simplify the model and improve stability.
1695
1743
 
1696
1744
  Args:
1697
1745
  parent: The index of the parent body
1698
1746
  child: The index of the child body
1699
- parent_xform: The transform of the joint in the parent body's local frame
1700
- xform: The transform of the joint in the child body's local frame
1747
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1748
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1701
1749
  linear_compliance: The linear compliance of the joint
1702
1750
  angular_compliance: The angular compliance of the joint
1703
1751
  name: The name of the joint
@@ -1705,7 +1753,7 @@ class ModelBuilder:
1705
1753
  enabled: Whether the joint is enabled
1706
1754
 
1707
1755
  Returns:
1708
- The index of the child body
1756
+ The index of the added joint
1709
1757
 
1710
1758
  """
1711
1759
  return self.add_joint(
@@ -1731,19 +1779,20 @@ class ModelBuilder:
1731
1779
  collision_filter_parent: bool = True,
1732
1780
  enabled: bool = True,
1733
1781
  ) -> int:
1734
- """Adds a free joint to the model
1782
+ """Adds a free joint to the model.
1783
+ It has 7 positional degrees of freedom (first 3 linear and then 4 angular dimensions for the orientation quaternion in `xyzw` notation) and 6 velocity degrees of freedom (first 3 angular and then 3 linear velocity dimensions).
1735
1784
 
1736
1785
  Args:
1737
- parent: The index of the parent body
1738
1786
  child: The index of the child body
1739
- parent_xform: The transform of the joint in the parent body's local frame
1740
- xform: The transform of the joint in the child body's local frame
1787
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1788
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1789
+ parent: The index of the parent body (-1 by default to use the world frame, e.g. to make the child body and its children a floating-base mechanism)
1741
1790
  name: The name of the joint
1742
1791
  collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
1743
1792
  enabled: Whether the joint is enabled
1744
1793
 
1745
1794
  Returns:
1746
- The index of the child body
1795
+ The index of the added joint
1747
1796
 
1748
1797
  """
1749
1798
  return self.add_joint(
@@ -1769,13 +1818,14 @@ class ModelBuilder:
1769
1818
  collision_filter_parent: bool = True,
1770
1819
  enabled: bool = True,
1771
1820
  ) -> int:
1772
- """Adds a distance joint to the model
1821
+ """Adds a distance joint to the model. The distance joint constraints the distance between the joint anchor points on the two bodies (see :ref:`FK-IK`) it connects to the interval [`min_distance`, `max_distance`].
1822
+ It has 7 positional degrees of freedom (first 3 linear and then 4 angular dimensions for the orientation quaternion in `xyzw` notation) and 6 velocity degrees of freedom (first 3 angular and then 3 linear velocity dimensions).
1773
1823
 
1774
1824
  Args:
1775
1825
  parent: The index of the parent body
1776
1826
  child: The index of the child body
1777
- parent_xform: The transform of the joint in the parent body's local frame
1778
- xform: The transform of the joint in the child body's local frame
1827
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1828
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1779
1829
  min_distance: The minimum distance between the bodies (no limit if negative)
1780
1830
  max_distance: The maximum distance between the bodies (no limit if negative)
1781
1831
  compliance: The compliance of the joint
@@ -1783,7 +1833,9 @@ class ModelBuilder:
1783
1833
  enabled: Whether the joint is enabled
1784
1834
 
1785
1835
  Returns:
1786
- The index of the child body
1836
+ The index of the added joint
1837
+
1838
+ .. note:: Distance joints are currently only supported in the :class:`XPBDIntegrator` at the moment.
1787
1839
 
1788
1840
  """
1789
1841
  ax = JointAxis(
@@ -1817,15 +1869,15 @@ class ModelBuilder:
1817
1869
  collision_filter_parent: bool = True,
1818
1870
  enabled: bool = True,
1819
1871
  ) -> int:
1820
- """Adds a universal joint to the model
1872
+ """Adds a universal joint to the model. U-joints have two degrees of freedom, one for each axis.
1821
1873
 
1822
1874
  Args:
1823
1875
  parent: The index of the parent body
1824
1876
  child: The index of the child body
1825
- axis_0: The first axis of the joint
1826
- axis_1: The second axis of the joint
1827
- parent_xform: The transform of the joint in the parent body's local frame
1828
- xform: The transform of the joint in the child body's local frame
1877
+ axis_0 (3D vector or JointAxis): The first axis of the joint, can be a JointAxis object whose settings will be used instead of the other arguments
1878
+ axis_1 (3D vector or JointAxis): The second axis of the joint, can be a JointAxis object whose settings will be used instead of the other arguments
1879
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1880
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1829
1881
  linear_compliance: The linear compliance of the joint
1830
1882
  angular_compliance: The angular compliance of the joint
1831
1883
  name: The name of the joint
@@ -1833,14 +1885,14 @@ class ModelBuilder:
1833
1885
  enabled: Whether the joint is enabled
1834
1886
 
1835
1887
  Returns:
1836
- The index of the child body
1888
+ The index of the added joint
1837
1889
 
1838
1890
  """
1839
1891
  return self.add_joint(
1840
1892
  JOINT_UNIVERSAL,
1841
1893
  parent,
1842
1894
  child,
1843
- angular_axes=[axis_0, axis_1],
1895
+ angular_axes=[JointAxis(axis_0), JointAxis(axis_1)],
1844
1896
  parent_xform=parent_xform,
1845
1897
  child_xform=child_xform,
1846
1898
  linear_compliance=linear_compliance,
@@ -1863,29 +1915,32 @@ class ModelBuilder:
1863
1915
  collision_filter_parent: bool = True,
1864
1916
  enabled: bool = True,
1865
1917
  ) -> int:
1866
- """Adds a compound joint to the model
1918
+ """Adds a compound joint to the model, which has 3 degrees of freedom, one for each axis.
1919
+ Similar to the ball joint (see :meth:`add_ball_joint`), the compound joint allows bodies to move in a 3D rotation relative to each other,
1920
+ except that the rotation is defined by 3 axes instead of a quaternion.
1921
+ Depending on the choice of axes, the orientation can be specified through Euler angles, e.g. `z-x-z` or `x-y-x`, or through a Tait-Bryan angle sequence, e.g. `z-y-x` or `x-y-z`.
1867
1922
 
1868
1923
  Args:
1869
1924
  parent: The index of the parent body
1870
1925
  child: The index of the child body
1871
- axis_0: The first axis of the joint
1872
- axis_1: The second axis of the joint
1873
- axis_2: The third axis of the joint
1874
- parent_xform: The transform of the joint in the parent body's local frame
1875
- xform: The transform of the joint in the child body's local frame
1926
+ axis_0 (3D vector or JointAxis): The first axis of the joint, can be a JointAxis object whose settings will be used instead of the other arguments
1927
+ axis_1 (3D vector or JointAxis): The second axis of the joint, can be a JointAxis object whose settings will be used instead of the other arguments
1928
+ axis_2 (3D vector or JointAxis): The third axis of the joint, can be a JointAxis object whose settings will be used instead of the other arguments
1929
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1930
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1876
1931
  name: The name of the joint
1877
1932
  collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
1878
1933
  enabled: Whether the joint is enabled
1879
1934
 
1880
1935
  Returns:
1881
- The index of the child body
1936
+ The index of the added joint
1882
1937
 
1883
1938
  """
1884
1939
  return self.add_joint(
1885
1940
  JOINT_COMPOUND,
1886
1941
  parent,
1887
1942
  child,
1888
- angular_axes=[axis_0, axis_1, axis_2],
1943
+ angular_axes=[JointAxis(axis_0), JointAxis(axis_1), JointAxis(axis_2)],
1889
1944
  parent_xform=parent_xform,
1890
1945
  child_xform=child_xform,
1891
1946
  name=name,
@@ -1907,7 +1962,7 @@ class ModelBuilder:
1907
1962
  collision_filter_parent: bool = True,
1908
1963
  enabled: bool = True,
1909
1964
  ):
1910
- """Adds a generic joint with custom linear and angular axes.
1965
+ """Adds a generic joint with custom linear and angular axes. The number of axes determines the number of degrees of freedom of the joint.
1911
1966
 
1912
1967
  Args:
1913
1968
  parent: The index of the parent body
@@ -1915,15 +1970,15 @@ class ModelBuilder:
1915
1970
  linear_axes: A list of linear axes
1916
1971
  angular_axes: A list of angular axes
1917
1972
  name: The name of the joint
1918
- parent_xform: The transform of the joint in the parent body's local frame
1919
- xform: The transform of the joint in the child body's local frame
1973
+ parent_xform (:ref:`transform <transform>`): The transform of the joint in the parent body's local frame
1974
+ child_xform (:ref:`transform <transform>`): The transform of the joint in the child body's local frame
1920
1975
  linear_compliance: The linear compliance of the joint
1921
1976
  angular_compliance: The angular compliance of the joint
1922
1977
  collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
1923
1978
  enabled: Whether the joint is enabled
1924
1979
 
1925
1980
  Returns:
1926
- The index of the child body
1981
+ The index of the added joint
1927
1982
 
1928
1983
  """
1929
1984
  return self.add_joint(
@@ -1932,8 +1987,8 @@ class ModelBuilder:
1932
1987
  child,
1933
1988
  parent_xform=parent_xform,
1934
1989
  child_xform=child_xform,
1935
- linear_axes=linear_axes,
1936
- angular_axes=angular_axes,
1990
+ linear_axes=[JointAxis(a) for a in linear_axes],
1991
+ angular_axes=[JointAxis(a) for a in angular_axes],
1937
1992
  linear_compliance=linear_compliance,
1938
1993
  angular_compliance=angular_compliance,
1939
1994
  name=name,
@@ -1942,7 +1997,7 @@ class ModelBuilder:
1942
1997
  )
1943
1998
 
1944
1999
  def collapse_fixed_joints(self, verbose=wp.config.verbose):
1945
- """Removes fixed joints from the model and merges the bodies they connect."""
2000
+ """Removes fixed joints from the model and merges the bodies they connect. This is useful for simplifying the model for faster and more stable simulation."""
1946
2001
 
1947
2002
  body_data = {}
1948
2003
  body_children = {-1: []}
@@ -2191,7 +2246,7 @@ class ModelBuilder:
2191
2246
  def add_muscle(
2192
2247
  self, bodies: List[int], positions: List[Vec3], f0: float, lm: float, lt: float, lmax: float, pen: float
2193
2248
  ) -> float:
2194
- """Adds a muscle-tendon activation unit
2249
+ """Adds a muscle-tendon activation unit.
2195
2250
 
2196
2251
  Args:
2197
2252
  bodies: A list of body indices for each waypoint
@@ -2204,6 +2259,8 @@ class ModelBuilder:
2204
2259
  Returns:
2205
2260
  The index of the muscle in the model
2206
2261
 
2262
+ .. note:: The simulation support for muscles is in progress and not yet fully functional.
2263
+
2207
2264
  """
2208
2265
 
2209
2266
  n = len(bodies)
@@ -2239,7 +2296,7 @@ class ModelBuilder:
2239
2296
  """
2240
2297
  Adds a plane collision shape.
2241
2298
  If pos and rot are defined, the plane is assumed to have its normal as (0, 1, 0).
2242
- Otherwise, the plane equation is used.
2299
+ Otherwise, the plane equation defined through the `plane` argument is used.
2243
2300
 
2244
2301
  Args:
2245
2302
  plane: The plane equation in form a*x + b*y + c*z + d = 0
@@ -2256,6 +2313,9 @@ class ModelBuilder:
2256
2313
  thickness: The thickness of the plane (0 by default) for collision handling
2257
2314
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2258
2315
 
2316
+ Returns:
2317
+ The index of the added shape
2318
+
2259
2319
  """
2260
2320
  if pos is None or rot is None:
2261
2321
  # compute position and rotation from plane equation
@@ -2270,7 +2330,7 @@ class ModelBuilder:
2270
2330
  angle = np.arcsin(np.linalg.norm(c))
2271
2331
  axis = c / np.linalg.norm(c)
2272
2332
  rot = wp.quat_from_axis_angle(axis, angle)
2273
- scale = (width, length, 0.0)
2333
+ scale = wp.vec3(width, length, 0.0)
2274
2334
 
2275
2335
  return self._add_shape(
2276
2336
  body,
@@ -2308,7 +2368,7 @@ class ModelBuilder:
2308
2368
  """Adds a sphere collision shape to a body.
2309
2369
 
2310
2370
  Args:
2311
- body: The index of the parent body this shape belongs to
2371
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2312
2372
  pos: The location of the shape with respect to the parent frame
2313
2373
  rot: The rotation of the shape with respect to the parent frame
2314
2374
  radius: The radius of the sphere
@@ -2322,14 +2382,17 @@ class ModelBuilder:
2322
2382
  thickness: Thickness to use for computing inertia of a hollow sphere, and for collision handling
2323
2383
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2324
2384
 
2385
+ Returns:
2386
+ The index of the added shape
2387
+
2325
2388
  """
2326
2389
 
2327
2390
  return self._add_shape(
2328
2391
  body,
2329
- pos,
2330
- rot,
2392
+ wp.vec3(pos),
2393
+ wp.quat(rot),
2331
2394
  GEO_SPHERE,
2332
- (radius, 0.0, 0.0, 0.0),
2395
+ wp.vec3(radius, 0.0, 0.0),
2333
2396
  None,
2334
2397
  density,
2335
2398
  ke,
@@ -2363,7 +2426,7 @@ class ModelBuilder:
2363
2426
  """Adds a box collision shape to a body.
2364
2427
 
2365
2428
  Args:
2366
- body: The index of the parent body this shape belongs to
2429
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2367
2430
  pos: The location of the shape with respect to the parent frame
2368
2431
  rot: The rotation of the shape with respect to the parent frame
2369
2432
  hx: The half-extent along the x-axis
@@ -2379,14 +2442,17 @@ class ModelBuilder:
2379
2442
  thickness: Thickness to use for computing inertia of a hollow box, and for collision handling
2380
2443
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2381
2444
 
2445
+ Returns:
2446
+ The index of the added shape
2447
+
2382
2448
  """
2383
2449
 
2384
2450
  return self._add_shape(
2385
2451
  body,
2386
- pos,
2387
- rot,
2452
+ wp.vec3(pos),
2453
+ wp.quat(rot),
2388
2454
  GEO_BOX,
2389
- (hx, hy, hz, 0.0),
2455
+ wp.vec3(hx, hy, hz),
2390
2456
  None,
2391
2457
  density,
2392
2458
  ke,
@@ -2420,7 +2486,7 @@ class ModelBuilder:
2420
2486
  """Adds a capsule collision shape to a body.
2421
2487
 
2422
2488
  Args:
2423
- body: The index of the parent body this shape belongs to
2489
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2424
2490
  pos: The location of the shape with respect to the parent frame
2425
2491
  rot: The rotation of the shape with respect to the parent frame
2426
2492
  radius: The radius of the capsule
@@ -2436,21 +2502,24 @@ class ModelBuilder:
2436
2502
  thickness: Thickness to use for computing inertia of a hollow capsule, and for collision handling
2437
2503
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2438
2504
 
2505
+ Returns:
2506
+ The index of the added shape
2507
+
2439
2508
  """
2440
2509
 
2441
- q = rot
2510
+ q = wp.quat(rot)
2442
2511
  sqh = math.sqrt(0.5)
2443
2512
  if up_axis == 0:
2444
- q = wp.mul(rot, wp.quat(0.0, 0.0, -sqh, sqh))
2513
+ q = wp.mul(q, wp.quat(0.0, 0.0, -sqh, sqh))
2445
2514
  elif up_axis == 2:
2446
- q = wp.mul(rot, wp.quat(sqh, 0.0, 0.0, sqh))
2515
+ q = wp.mul(q, wp.quat(sqh, 0.0, 0.0, sqh))
2447
2516
 
2448
2517
  return self._add_shape(
2449
2518
  body,
2450
- pos,
2451
- q,
2519
+ wp.vec3(pos),
2520
+ wp.quat(q),
2452
2521
  GEO_CAPSULE,
2453
- (radius, half_height, 0.0, 0.0),
2522
+ wp.vec3(radius, half_height, 0.0),
2454
2523
  None,
2455
2524
  density,
2456
2525
  ke,
@@ -2484,7 +2553,7 @@ class ModelBuilder:
2484
2553
  """Adds a cylinder collision shape to a body.
2485
2554
 
2486
2555
  Args:
2487
- body: The index of the parent body this shape belongs to
2556
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2488
2557
  pos: The location of the shape with respect to the parent frame
2489
2558
  rot: The rotation of the shape with respect to the parent frame
2490
2559
  radius: The radius of the cylinder
@@ -2500,6 +2569,9 @@ class ModelBuilder:
2500
2569
  thickness: Thickness to use for computing inertia of a hollow cylinder, and for collision handling
2501
2570
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2502
2571
 
2572
+ Returns:
2573
+ The index of the added shape
2574
+
2503
2575
  """
2504
2576
 
2505
2577
  q = rot
@@ -2511,10 +2583,10 @@ class ModelBuilder:
2511
2583
 
2512
2584
  return self._add_shape(
2513
2585
  body,
2514
- pos,
2515
- q,
2586
+ wp.vec3(pos),
2587
+ wp.quat(q),
2516
2588
  GEO_CYLINDER,
2517
- (radius, half_height, 0.0, 0.0),
2589
+ wp.vec3(radius, half_height, 0.0),
2518
2590
  None,
2519
2591
  density,
2520
2592
  ke,
@@ -2548,7 +2620,7 @@ class ModelBuilder:
2548
2620
  """Adds a cone collision shape to a body.
2549
2621
 
2550
2622
  Args:
2551
- body: The index of the parent body this shape belongs to
2623
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2552
2624
  pos: The location of the shape with respect to the parent frame
2553
2625
  rot: The rotation of the shape with respect to the parent frame
2554
2626
  radius: The radius of the cone
@@ -2564,6 +2636,9 @@ class ModelBuilder:
2564
2636
  thickness: Thickness to use for computing inertia of a hollow cone, and for collision handling
2565
2637
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2566
2638
 
2639
+ Returns:
2640
+ The index of the added shape
2641
+
2567
2642
  """
2568
2643
 
2569
2644
  q = rot
@@ -2575,10 +2650,10 @@ class ModelBuilder:
2575
2650
 
2576
2651
  return self._add_shape(
2577
2652
  body,
2578
- pos,
2579
- q,
2653
+ wp.vec3(pos),
2654
+ wp.quat(q),
2580
2655
  GEO_CONE,
2581
- (radius, half_height, 0.0, 0.0),
2656
+ wp.vec3(radius, half_height, 0.0),
2582
2657
  None,
2583
2658
  density,
2584
2659
  ke,
@@ -2594,10 +2669,10 @@ class ModelBuilder:
2594
2669
  def add_shape_mesh(
2595
2670
  self,
2596
2671
  body: int,
2597
- pos: Vec3 = (0.0, 0.0, 0.0),
2598
- rot: Quat = (0.0, 0.0, 0.0, 1.0),
2672
+ pos: Vec3 = wp.vec3(0.0, 0.0, 0.0),
2673
+ rot: Quat = wp.quat(0.0, 0.0, 0.0, 1.0),
2599
2674
  mesh: Mesh = None,
2600
- scale: Vec3 = (1.0, 1.0, 1.0),
2675
+ scale: Vec3 = wp.vec3(1.0, 1.0, 1.0),
2601
2676
  density: float = default_shape_density,
2602
2677
  ke: float = default_shape_ke,
2603
2678
  kd: float = default_shape_kd,
@@ -2611,7 +2686,7 @@ class ModelBuilder:
2611
2686
  """Adds a triangle mesh collision shape to a body.
2612
2687
 
2613
2688
  Args:
2614
- body: The index of the parent body this shape belongs to
2689
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2615
2690
  pos: The location of the shape with respect to the parent frame
2616
2691
  rot: The rotation of the shape with respect to the parent frame
2617
2692
  mesh: The mesh object
@@ -2626,6 +2701,9 @@ class ModelBuilder:
2626
2701
  thickness: Thickness to use for computing inertia of a hollow mesh, and for collision handling
2627
2702
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2628
2703
 
2704
+ Returns:
2705
+ The index of the added shape
2706
+
2629
2707
  """
2630
2708
 
2631
2709
  return self._add_shape(
@@ -2633,7 +2711,7 @@ class ModelBuilder:
2633
2711
  pos,
2634
2712
  rot,
2635
2713
  GEO_MESH,
2636
- (scale[0], scale[1], scale[2], 0.0),
2714
+ wp.vec3(scale[0], scale[1], scale[2]),
2637
2715
  mesh,
2638
2716
  density,
2639
2717
  ke,
@@ -2665,7 +2743,7 @@ class ModelBuilder:
2665
2743
  """Adds SDF collision shape to a body.
2666
2744
 
2667
2745
  Args:
2668
- body: The index of the parent body this shape belongs to
2746
+ body: The index of the parent body this shape belongs to (use -1 for static shapes)
2669
2747
  pos: The location of the shape with respect to the parent frame
2670
2748
  rot: The rotation of the shape with respect to the parent frame
2671
2749
  sdf: The sdf object
@@ -2680,13 +2758,16 @@ class ModelBuilder:
2680
2758
  thickness: Thickness to use for computing inertia of a hollow mesh, and for collision handling
2681
2759
  has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
2682
2760
 
2761
+ Returns:
2762
+ The index of the added shape
2763
+
2683
2764
  """
2684
2765
  return self._add_shape(
2685
2766
  body,
2686
- pos,
2687
- rot,
2767
+ wp.vec3(pos),
2768
+ wp.quat(rot),
2688
2769
  GEO_SDF,
2689
- (scale[0], scale[1], scale[2], 0.0),
2770
+ wp.vec3(scale[0], scale[1], scale[2]),
2690
2771
  sdf,
2691
2772
  density,
2692
2773
  ke,
@@ -2777,7 +2858,7 @@ class ModelBuilder:
2777
2858
 
2778
2859
  (m, c, I) = compute_shape_mass(type, scale, src, density, is_solid, thickness)
2779
2860
 
2780
- self._update_body_mass(body, m, I, np.array(pos) + c, np.array(rot))
2861
+ self._update_body_mass(body, m, I, pos + c, rot)
2781
2862
  return shape
2782
2863
 
2783
2864
  # particles
@@ -2872,9 +2953,9 @@ class ModelBuilder:
2872
2953
 
2873
2954
  """
2874
2955
  # compute basis for 2D rest pose
2875
- p = np.array(self.particle_q[i])
2876
- q = np.array(self.particle_q[j])
2877
- r = np.array(self.particle_q[k])
2956
+ p = self.particle_q[i]
2957
+ q = self.particle_q[j]
2958
+ r = self.particle_q[k]
2878
2959
 
2879
2960
  qp = q - p
2880
2961
  rp = r - p
@@ -3012,7 +3093,7 @@ class ModelBuilder:
3012
3093
  The volume of the tetrahedron
3013
3094
 
3014
3095
  Note:
3015
- The tetrahedron is created with a rest-pose based on the particle's initial configruation
3096
+ The tetrahedron is created with a rest-pose based on the particle's initial configuration
3016
3097
 
3017
3098
  """
3018
3099
  # compute basis for 2D rest pose
@@ -3071,13 +3152,13 @@ class ModelBuilder:
3071
3152
  """
3072
3153
  # compute rest angle
3073
3154
  if rest is None:
3074
- x1 = np.array(self.particle_q[i])
3075
- x2 = np.array(self.particle_q[j])
3076
- x3 = np.array(self.particle_q[k])
3077
- x4 = np.array(self.particle_q[l])
3155
+ x1 = self.particle_q[i]
3156
+ x2 = self.particle_q[j]
3157
+ x3 = self.particle_q[k]
3158
+ x4 = self.particle_q[l]
3078
3159
 
3079
- n1 = wp.normalize(np.cross(x3 - x1, x4 - x1))
3080
- n2 = wp.normalize(np.cross(x4 - x2, x3 - x2))
3160
+ n1 = wp.normalize(wp.cross(x3 - x1, x4 - x1))
3161
+ n2 = wp.normalize(wp.cross(x4 - x2, x3 - x2))
3081
3162
  e = wp.normalize(x4 - x3)
3082
3163
 
3083
3164
  d = np.clip(np.dot(n2, n1), -1.0, 1.0)
@@ -3217,8 +3298,8 @@ class ModelBuilder:
3217
3298
 
3218
3299
  for y in range(0, dim_y + 1):
3219
3300
  for x in range(0, dim_x + 1):
3220
- g = np.array((x * cell_x, y * cell_y, 0.0))
3221
- p = np.array(wp.quat_rotate(rot, g)) + pos
3301
+ g = wp.vec3(x * cell_x, y * cell_y, 0.0)
3302
+ p = wp.quat_rotate(rot, g) + pos
3222
3303
  m = mass
3223
3304
 
3224
3305
  if x == 0 and fix_left:
@@ -3265,7 +3346,6 @@ class ModelBuilder:
3265
3346
  self.add_triangle(*tri1, tri_ke, tri_ka, tri_kd, tri_drag, tri_lift)
3266
3347
  self.add_triangle(*tri2, tri_ke, tri_ka, tri_kd, tri_drag, tri_lift)
3267
3348
 
3268
- end_vertex = len(self.particle_q)
3269
3349
  end_tri = len(self.tri_indices)
3270
3350
 
3271
3351
  # bending constraints, could create these explicitly for a grid but this
@@ -3344,7 +3424,7 @@ class ModelBuilder:
3344
3424
 
3345
3425
  # particles
3346
3426
  for v in vertices:
3347
- p = np.array(wp.quat_rotate(rot, v * scale)) + pos
3427
+ p = wp.quat_rotate(rot, v * scale) + pos
3348
3428
 
3349
3429
  self.add_particle(p, vel, 0.0)
3350
3430
 
@@ -3417,13 +3497,14 @@ class ModelBuilder:
3417
3497
  radius_mean: float = default_particle_radius,
3418
3498
  radius_std: float = 0.0,
3419
3499
  ):
3500
+ rng = np.random.default_rng()
3420
3501
  for z in range(dim_z):
3421
3502
  for y in range(dim_y):
3422
3503
  for x in range(dim_x):
3423
- v = np.array((x * cell_x, y * cell_y, z * cell_z))
3504
+ v = wp.vec3(x * cell_x, y * cell_y, z * cell_z)
3424
3505
  m = mass
3425
3506
 
3426
- p = np.array(wp.quat_rotate(rot, v)) + pos + np.random.rand(3) * jitter
3507
+ p = wp.quat_rotate(rot, v) + pos + wp.vec3(rng.random(3) * jitter)
3427
3508
 
3428
3509
  if radius_std > 0.0:
3429
3510
  r = radius_mean + np.random.randn() * radius_std
@@ -3489,7 +3570,7 @@ class ModelBuilder:
3489
3570
  for z in range(dim_z + 1):
3490
3571
  for y in range(dim_y + 1):
3491
3572
  for x in range(dim_x + 1):
3492
- v = np.array((x * cell_x, y * cell_y, z * cell_z))
3573
+ v = wp.vec3(x * cell_x, y * cell_y, z * cell_z)
3493
3574
  m = mass
3494
3575
 
3495
3576
  if fix_left and x == 0:
@@ -3504,7 +3585,7 @@ class ModelBuilder:
3504
3585
  if fix_bottom and y == 0:
3505
3586
  m = 0.0
3506
3587
 
3507
- p = np.array(wp.quat_rotate(rot, v)) + pos
3588
+ p = wp.quat_rotate(rot, v) + pos
3508
3589
 
3509
3590
  self.add_particle(p, vel, m)
3510
3591
 
@@ -3594,7 +3675,6 @@ class ModelBuilder:
3594
3675
  num_tets = int(len(indices) / 4)
3595
3676
 
3596
3677
  start_vertex = len(self.particle_q)
3597
- start_tri = len(self.tri_indices)
3598
3678
 
3599
3679
  # dict of open faces
3600
3680
  faces = {}
@@ -3672,8 +3752,8 @@ class ModelBuilder:
3672
3752
  else:
3673
3753
  self.body_inv_mass[i] = 0.0
3674
3754
 
3675
- if new_inertia.any():
3676
- self.body_inv_inertia[i] = np.linalg.inv(new_inertia)
3755
+ if any(x for x in new_inertia):
3756
+ self.body_inv_inertia[i] = wp.inverse(new_inertia)
3677
3757
  else:
3678
3758
  self.body_inv_inertia[i] = new_inertia
3679
3759