warp-lang 1.7.0__py3-none-win_amd64.whl → 1.7.1__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 (46) hide show
  1. warp/autograd.py +12 -2
  2. warp/bin/warp-clang.dll +0 -0
  3. warp/bin/warp.dll +0 -0
  4. warp/build.py +1 -1
  5. warp/builtins.py +11 -10
  6. warp/codegen.py +17 -5
  7. warp/config.py +1 -1
  8. warp/context.py +6 -0
  9. warp/examples/benchmarks/benchmark_cloth.py +1 -1
  10. warp/examples/distributed/example_jacobi_mpi.py +507 -0
  11. warp/fem/field/field.py +11 -1
  12. warp/fem/field/nodal_field.py +36 -22
  13. warp/fem/geometry/adaptive_nanogrid.py +7 -3
  14. warp/fem/geometry/trimesh.py +4 -12
  15. warp/jax_experimental/custom_call.py +14 -2
  16. warp/jax_experimental/ffi.py +5 -1
  17. warp/native/tile.h +11 -11
  18. warp/native/warp.cu +1 -1
  19. warp/render/render_opengl.py +19 -17
  20. warp/render/render_usd.py +93 -3
  21. warp/sim/collide.py +11 -9
  22. warp/sim/inertia.py +189 -156
  23. warp/sim/integrator_euler.py +3 -0
  24. warp/sim/integrator_xpbd.py +3 -0
  25. warp/sim/model.py +29 -12
  26. warp/sim/render.py +4 -0
  27. warp/stubs.py +1 -1
  28. warp/tests/assets/torus.usda +1 -1
  29. warp/tests/sim/test_collision.py +237 -206
  30. warp/tests/sim/test_inertia.py +161 -0
  31. warp/tests/sim/{flaky_test_sim_grad.py → test_sim_grad.py} +4 -0
  32. warp/tests/sim/test_xpbd.py +399 -0
  33. warp/tests/test_codegen.py +24 -3
  34. warp/tests/test_examples.py +16 -6
  35. warp/tests/test_fem.py +75 -10
  36. warp/tests/test_mat.py +370 -103
  37. warp/tests/test_quat.py +321 -137
  38. warp/tests/test_vec.py +320 -174
  39. warp/tests/tile/test_tile_load.py +97 -0
  40. warp/tests/unittest_suites.py +2 -5
  41. warp/types.py +65 -8
  42. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/METADATA +21 -9
  43. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/RECORD +46 -43
  44. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/WHEEL +1 -1
  45. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/licenses/LICENSE.md +0 -26
  46. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/top_level.txt +0 -0
warp/sim/inertia.py CHANGED
@@ -15,131 +15,14 @@
15
15
 
16
16
  """Helper functions for computing rigid body inertia properties."""
17
17
 
18
- import math
19
- from typing import List, Union
18
+ from __future__ import annotations
20
19
 
21
20
  import numpy as np
22
21
 
23
22
  import warp as wp
24
23
 
25
24
 
26
- @wp.func
27
- def triangle_inertia(
28
- p: wp.vec3,
29
- q: wp.vec3,
30
- r: wp.vec3,
31
- density: float,
32
- com: wp.vec3,
33
- # outputs
34
- mass: wp.array(dtype=float, ndim=1),
35
- inertia: wp.array(dtype=wp.mat33, ndim=1),
36
- ):
37
- pcom = p - com
38
- qcom = q - com
39
- rcom = r - com
40
-
41
- Dm = wp.mat33(pcom[0], qcom[0], rcom[0], pcom[1], qcom[1], rcom[1], pcom[2], qcom[2], rcom[2])
42
-
43
- volume = wp.abs(wp.determinant(Dm) / 6.0)
44
-
45
- # accumulate mass
46
- wp.atomic_add(mass, 0, 4.0 * density * volume)
47
-
48
- alpha = wp.sqrt(5.0) / 5.0
49
- mid = (com + p + q + r) / 4.0
50
- off_mid = mid - com
51
-
52
- # displacement of quadrature point from COM
53
- d0 = alpha * (p - mid) + off_mid
54
- d1 = alpha * (q - mid) + off_mid
55
- d2 = alpha * (r - mid) + off_mid
56
- d3 = alpha * (com - mid) + off_mid
57
-
58
- # accumulate inertia
59
- identity = wp.mat33(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
60
- I = wp.dot(d0, d0) * identity - wp.outer(d0, d0)
61
- I += wp.dot(d1, d1) * identity - wp.outer(d1, d1)
62
- I += wp.dot(d2, d2) * identity - wp.outer(d2, d2)
63
- I += wp.dot(d3, d3) * identity - wp.outer(d3, d3)
64
-
65
- wp.atomic_add(inertia, 0, (density * volume) * I)
66
-
67
- return volume
68
-
69
-
70
- @wp.kernel
71
- def compute_solid_mesh_inertia(
72
- # inputs
73
- com: wp.vec3,
74
- weight: float,
75
- indices: wp.array(dtype=int, ndim=1),
76
- vertices: wp.array(dtype=wp.vec3, ndim=1),
77
- # outputs
78
- mass: wp.array(dtype=float, ndim=1),
79
- inertia: wp.array(dtype=wp.mat33, ndim=1),
80
- volume: wp.array(dtype=float, ndim=1),
81
- ):
82
- i = wp.tid()
83
-
84
- p = vertices[indices[i * 3 + 0]]
85
- q = vertices[indices[i * 3 + 1]]
86
- r = vertices[indices[i * 3 + 2]]
87
-
88
- vol = triangle_inertia(p, q, r, weight, com, mass, inertia)
89
- wp.atomic_add(volume, 0, vol)
90
-
91
-
92
- @wp.kernel
93
- def compute_hollow_mesh_inertia(
94
- # inputs
95
- com: wp.vec3,
96
- density: float,
97
- indices: wp.array(dtype=int, ndim=1),
98
- vertices: wp.array(dtype=wp.vec3, ndim=1),
99
- thickness: wp.array(dtype=float, ndim=1),
100
- # outputs
101
- mass: wp.array(dtype=float, ndim=1),
102
- inertia: wp.array(dtype=wp.mat33, ndim=1),
103
- volume: wp.array(dtype=float, ndim=1),
104
- ):
105
- tid = wp.tid()
106
- i = indices[tid * 3 + 0]
107
- j = indices[tid * 3 + 1]
108
- k = indices[tid * 3 + 2]
109
-
110
- vi = vertices[i]
111
- vj = vertices[j]
112
- vk = vertices[k]
113
-
114
- normal = -wp.normalize(wp.cross(vj - vi, vk - vi))
115
- ti = normal * thickness[i]
116
- tj = normal * thickness[j]
117
- tk = normal * thickness[k]
118
-
119
- # wedge vertices
120
- vi0 = vi - ti
121
- vi1 = vi + ti
122
- vj0 = vj - tj
123
- vj1 = vj + tj
124
- vk0 = vk - tk
125
- vk1 = vk + tk
126
-
127
- triangle_inertia(vi0, vj0, vk0, density, com, mass, inertia)
128
- triangle_inertia(vj0, vk1, vk0, density, com, mass, inertia)
129
- triangle_inertia(vj0, vj1, vk1, density, com, mass, inertia)
130
- triangle_inertia(vj0, vi1, vj1, density, com, mass, inertia)
131
- triangle_inertia(vj0, vi0, vi1, density, com, mass, inertia)
132
- triangle_inertia(vj1, vi1, vk1, density, com, mass, inertia)
133
- triangle_inertia(vi1, vi0, vk0, density, com, mass, inertia)
134
- triangle_inertia(vi1, vk0, vk1, density, com, mass, inertia)
135
-
136
- # compute volume
137
- a = wp.length(wp.cross(vj - vi, vk - vi)) * 0.5
138
- vol = a * (thickness[i] + thickness[j] + thickness[k]) / 3.0
139
- wp.atomic_add(volume, 0, vol)
140
-
141
-
142
- def compute_sphere_inertia(density: float, r: float) -> tuple:
25
+ def compute_sphere_inertia(density: float, r: float) -> tuple[float, wp.vec3, wp.mat33]:
143
26
  """Helper to compute mass and inertia of a solid sphere
144
27
 
145
28
  Args:
@@ -151,7 +34,7 @@ def compute_sphere_inertia(density: float, r: float) -> tuple:
151
34
  A tuple of (mass, inertia) with inertia specified around the origin
152
35
  """
153
36
 
154
- v = 4.0 / 3.0 * math.pi * r * r * r
37
+ v = 4.0 / 3.0 * wp.pi * r * r * r
155
38
 
156
39
  m = density * v
157
40
  Ia = 2.0 / 5.0 * m * r * r
@@ -161,7 +44,7 @@ def compute_sphere_inertia(density: float, r: float) -> tuple:
161
44
  return (m, wp.vec3(), I)
162
45
 
163
46
 
164
- def compute_capsule_inertia(density: float, r: float, h: float) -> tuple:
47
+ def compute_capsule_inertia(density: float, r: float, h: float) -> tuple[float, wp.vec3, wp.mat33]:
165
48
  """Helper to compute mass and inertia of a solid capsule extending along the y-axis
166
49
 
167
50
  Args:
@@ -174,8 +57,8 @@ def compute_capsule_inertia(density: float, r: float, h: float) -> tuple:
174
57
  A tuple of (mass, inertia) with inertia specified around the origin
175
58
  """
176
59
 
177
- ms = density * (4.0 / 3.0) * math.pi * r * r * r
178
- mc = density * math.pi * r * r * h
60
+ ms = density * (4.0 / 3.0) * wp.pi * r * r * r
61
+ mc = density * wp.pi * r * r * h
179
62
 
180
63
  # total mass
181
64
  m = ms + mc
@@ -189,7 +72,7 @@ def compute_capsule_inertia(density: float, r: float, h: float) -> tuple:
189
72
  return (m, wp.vec3(), I)
190
73
 
191
74
 
192
- def compute_cylinder_inertia(density: float, r: float, h: float) -> tuple:
75
+ def compute_cylinder_inertia(density: float, r: float, h: float) -> tuple[float, wp.vec3, wp.mat33]:
193
76
  """Helper to compute mass and inertia of a solid cylinder extending along the y-axis
194
77
 
195
78
  Args:
@@ -202,7 +85,7 @@ def compute_cylinder_inertia(density: float, r: float, h: float) -> tuple:
202
85
  A tuple of (mass, inertia) with inertia specified around the origin
203
86
  """
204
87
 
205
- m = density * math.pi * r * r * h
88
+ m = density * wp.pi * r * r * h
206
89
 
207
90
  Ia = 1 / 12 * m * (3 * r * r + h * h)
208
91
  Ib = 1 / 2 * m * r * r
@@ -212,7 +95,7 @@ def compute_cylinder_inertia(density: float, r: float, h: float) -> tuple:
212
95
  return (m, wp.vec3(), I)
213
96
 
214
97
 
215
- def compute_cone_inertia(density: float, r: float, h: float) -> tuple:
98
+ def compute_cone_inertia(density: float, r: float, h: float) -> tuple[float, wp.vec3, wp.mat33]:
216
99
  """Helper to compute mass and inertia of a solid cone extending along the y-axis
217
100
 
218
101
  Args:
@@ -225,7 +108,7 @@ def compute_cone_inertia(density: float, r: float, h: float) -> tuple:
225
108
  A tuple of (mass, inertia) with inertia specified around the origin
226
109
  """
227
110
 
228
- m = density * math.pi * r * r * h / 3.0
111
+ m = density * wp.pi * r * r * h / 3.0
229
112
 
230
113
  Ia = 1 / 20 * m * (3 * r * r + 2 * h * h)
231
114
  Ib = 3 / 10 * m * r * r
@@ -235,7 +118,7 @@ def compute_cone_inertia(density: float, r: float, h: float) -> tuple:
235
118
  return (m, wp.vec3(), I)
236
119
 
237
120
 
238
- def compute_box_inertia(density: float, w: float, h: float, d: float) -> tuple:
121
+ def compute_box_inertia(density: float, w: float, h: float, d: float) -> tuple[float, wp.vec3, wp.mat33]:
239
122
  """Helper to compute mass and inertia of a solid box
240
123
 
241
124
  Args:
@@ -261,63 +144,213 @@ def compute_box_inertia(density: float, w: float, h: float, d: float) -> tuple:
261
144
  return (m, wp.vec3(), I)
262
145
 
263
146
 
147
+ @wp.func
148
+ def triangle_inertia(
149
+ v0: wp.vec3,
150
+ v1: wp.vec3,
151
+ v2: wp.vec3,
152
+ ):
153
+ vol = wp.dot(v0, wp.cross(v1, v2)) / 6.0 # tetra volume (0,v0,v1,v2)
154
+ first = vol * (v0 + v1 + v2) / 4.0 # first-order integral
155
+
156
+ # second-order integral (symmetric)
157
+ o00, o11, o22 = wp.outer(v0, v0), wp.outer(v1, v1), wp.outer(v2, v2)
158
+ o01, o02, o12 = wp.outer(v0, v1), wp.outer(v0, v2), wp.outer(v1, v2)
159
+ o01t, o02t, o12t = wp.transpose(o01), wp.transpose(o02), wp.transpose(o12)
160
+
161
+ second = (vol / 10.0) * (o00 + o11 + o22)
162
+ second += (vol / 20.0) * (o01 + o01t + o02 + o02t + o12 + o12t)
163
+
164
+ return vol, first, second
165
+
166
+
167
+ @wp.kernel
168
+ def compute_solid_mesh_inertia(
169
+ indices: wp.array(dtype=int),
170
+ vertices: wp.array(dtype=wp.vec3),
171
+ # outputs
172
+ volume: wp.array(dtype=float),
173
+ first: wp.array(dtype=wp.vec3),
174
+ second: wp.array(dtype=wp.mat33),
175
+ ):
176
+ i = wp.tid()
177
+ p = vertices[indices[i * 3 + 0]]
178
+ q = vertices[indices[i * 3 + 1]]
179
+ r = vertices[indices[i * 3 + 2]]
180
+
181
+ v, f, s = triangle_inertia(p, q, r)
182
+ wp.atomic_add(volume, 0, v)
183
+ wp.atomic_add(first, 0, f)
184
+ wp.atomic_add(second, 0, s)
185
+
186
+
187
+ @wp.kernel
188
+ def compute_hollow_mesh_inertia(
189
+ indices: wp.array(dtype=int),
190
+ vertices: wp.array(dtype=wp.vec3),
191
+ thickness: wp.array(dtype=float),
192
+ # outputs
193
+ volume: wp.array(dtype=float),
194
+ first: wp.array(dtype=wp.vec3),
195
+ second: wp.array(dtype=wp.mat33),
196
+ ):
197
+ tid = wp.tid()
198
+ i = indices[tid * 3 + 0]
199
+ j = indices[tid * 3 + 1]
200
+ k = indices[tid * 3 + 2]
201
+
202
+ vi = vertices[i]
203
+ vj = vertices[j]
204
+ vk = vertices[k]
205
+
206
+ normal = -wp.normalize(wp.cross(vj - vi, vk - vi))
207
+ ti = normal * thickness[i]
208
+ tj = normal * thickness[j]
209
+ tk = normal * thickness[k]
210
+
211
+ # wedge vertices
212
+ vi0 = vi - ti
213
+ vi1 = vi + ti
214
+ vj0 = vj - tj
215
+ vj1 = vj + tj
216
+ vk0 = vk - tk
217
+ vk1 = vk + tk
218
+
219
+ v_total = 0.0
220
+ f_total = wp.vec3(0.0)
221
+ s_total = wp.mat33(0.0)
222
+
223
+ v, f, s = triangle_inertia(vi0, vj0, vk0)
224
+ v_total += v
225
+ f_total += f
226
+ s_total += s
227
+ v, f, s = triangle_inertia(vj0, vk1, vk0)
228
+ v_total += v
229
+ f_total += f
230
+ s_total += s
231
+ v, f, s = triangle_inertia(vj0, vj1, vk1)
232
+ v_total += v
233
+ f_total += f
234
+ s_total += s
235
+ v, f, s = triangle_inertia(vj0, vi1, vj1)
236
+ v_total += v
237
+ f_total += f
238
+ s_total += s
239
+ v, f, s = triangle_inertia(vj0, vi0, vi1)
240
+ v_total += v
241
+ f_total += f
242
+ s_total += s
243
+ v, f, s = triangle_inertia(vj1, vi1, vk1)
244
+ v_total += v
245
+ f_total += f
246
+ s_total += s
247
+ v, f, s = triangle_inertia(vi1, vi0, vk0)
248
+ v_total += v
249
+ f_total += f
250
+ s_total += s
251
+ v, f, s = triangle_inertia(vi1, vk0, vk1)
252
+ v_total += v
253
+ f_total += f
254
+ s_total += s
255
+
256
+ wp.atomic_add(volume, 0, v_total)
257
+ wp.atomic_add(first, 0, f_total)
258
+ wp.atomic_add(second, 0, s_total)
259
+
260
+
264
261
  def compute_mesh_inertia(
265
- density: float, vertices: list, indices: list, is_solid: bool = True, thickness: Union[List[float], float] = 0.001
266
- ) -> tuple:
267
- """Computes mass, center of mass, 3x3 inertia matrix, and volume for a mesh."""
268
- com = wp.vec3(np.mean(vertices, 0))
262
+ density: float,
263
+ vertices: list,
264
+ indices: list,
265
+ is_solid: bool = True,
266
+ thickness: list[float] | float = 0.001,
267
+ ) -> tuple[float, wp.vec3, wp.mat33, float]:
268
+ """
269
+ Compute the mass, center of mass, inertia, and volume of a triangular mesh.
270
+
271
+ Args:
272
+ density: The density of the mesh material.
273
+ vertices: A list of vertex positions (3D coordinates).
274
+ indices: A list of triangle indices (each triangle is defined by 3 vertex indices).
275
+ is_solid: If True, compute inertia for a solid mesh; if False, for a hollow mesh using the given thickness.
276
+ thickness: Thickness of the mesh if it is hollow. Can be a single value or a list of values for each vertex.
277
+
278
+ Returns:
279
+ A tuple containing:
280
+ - mass: The mass of the mesh.
281
+ - com: The center of mass (3D coordinates).
282
+ - I: The inertia tensor (3x3 matrix).
283
+ - volume: The signed volume of the mesh.
284
+ """
269
285
 
270
286
  indices = np.array(indices).flatten()
271
287
  num_tris = len(indices) // 3
272
288
 
273
- # compute signed inertia for each tetrahedron
274
- # formed with the interior point, using an order-2
275
- # quadrature: https://www.sciencedirect.com/science/article/pii/S0377042712001604#br000040
276
-
277
289
  # Allocating for mass and inertia
290
+ com_warp = wp.zeros(1, dtype=wp.vec3)
278
291
  I_warp = wp.zeros(1, dtype=wp.mat33)
279
- mass_warp = wp.zeros(1, dtype=float)
280
292
  vol_warp = wp.zeros(1, dtype=float)
281
293
 
294
+ wp_vertices = wp.array(vertices, dtype=wp.vec3)
295
+ wp_indices = wp.array(indices, dtype=int)
296
+
282
297
  if is_solid:
283
- weight = 0.25
284
- # alpha = math.sqrt(5.0) / 5.0
285
298
  wp.launch(
286
299
  kernel=compute_solid_mesh_inertia,
287
300
  dim=num_tris,
288
301
  inputs=[
289
- com,
290
- weight,
291
- wp.array(indices, dtype=int),
292
- wp.array(vertices, dtype=wp.vec3),
302
+ wp_indices,
303
+ wp_vertices,
304
+ ],
305
+ outputs=[
306
+ vol_warp,
307
+ com_warp,
308
+ I_warp,
293
309
  ],
294
- outputs=[mass_warp, I_warp, vol_warp],
295
310
  )
296
311
  else:
297
- weight = 0.25 * density
298
312
  if isinstance(thickness, float):
299
313
  thickness = [thickness] * len(vertices)
300
314
  wp.launch(
301
315
  kernel=compute_hollow_mesh_inertia,
302
316
  dim=num_tris,
303
317
  inputs=[
304
- com,
305
- weight,
306
- wp.array(indices, dtype=int),
307
- wp.array(vertices, dtype=wp.vec3),
318
+ wp_indices,
319
+ wp_vertices,
308
320
  wp.array(thickness, dtype=float),
309
321
  ],
310
- outputs=[mass_warp, I_warp, vol_warp],
322
+ outputs=[
323
+ vol_warp,
324
+ com_warp,
325
+ I_warp,
326
+ ],
311
327
  )
312
328
 
313
- # Extract mass and inertia and save to class attributes.
314
- mass = float(mass_warp.numpy()[0] * density)
315
- I = wp.mat33(*(I_warp.numpy()[0] * density))
316
- volume = float(vol_warp.numpy()[0])
317
- return mass, com, I, volume
329
+ V_tot = float(vol_warp.numpy()[0]) # signed volume
330
+ F_tot = com_warp.numpy()[0] # first moment
331
+ S_tot = I_warp.numpy()[0] # second moment
332
+
333
+ # If the winding is inward, flip signs
334
+ if V_tot < 0:
335
+ V_tot = -V_tot
336
+ F_tot = -F_tot
337
+ S_tot = -S_tot
338
+
339
+ mass = density * V_tot
340
+ if V_tot > 0.0:
341
+ com = F_tot / V_tot
342
+ else:
343
+ com = F_tot
344
+
345
+ S_tot *= density # include density
346
+ I_origin = np.trace(S_tot) * np.eye(3) - S_tot # inertia about origin
347
+ r = com
348
+ I_com = I_origin - mass * ((r @ r) * np.eye(3) - np.outer(r, r))
349
+
350
+ return mass, wp.vec3(*com), wp.mat33(*I_com), V_tot
318
351
 
319
352
 
320
- def transform_inertia(m, I, p, q):
353
+ def transform_inertia(m, I, p, q) -> wp.mat33:
321
354
  R = wp.quat_to_matrix(q)
322
355
 
323
356
  # Steiner's theorem
@@ -42,6 +42,9 @@ def eval_springs(
42
42
  i = spring_indices[tid * 2 + 0]
43
43
  j = spring_indices[tid * 2 + 1]
44
44
 
45
+ if i == -1 or j == -1:
46
+ return
47
+
45
48
  ke = spring_stiffness[tid]
46
49
  kd = spring_damping[tid]
47
50
  rest = spring_rest_lengths[tid]
@@ -401,6 +401,9 @@ def solve_springs(
401
401
  i = spring_indices[tid * 2 + 0]
402
402
  j = spring_indices[tid * 2 + 1]
403
403
 
404
+ if i == -1 or j == -1:
405
+ return
406
+
404
407
  ke = spring_stiffness[tid]
405
408
  kd = spring_damping[tid]
406
409
  rest = spring_rest_lengths[tid]
warp/sim/model.py CHANGED
@@ -633,6 +633,7 @@ class Model:
633
633
  soft_contact_body_pos (array), Positional offset of soft contact point in body frame, shape [soft_contact_max], vec3
634
634
  soft_contact_body_vel (array), Linear velocity of soft contact point in body frame, shape [soft_contact_max], vec3
635
635
  soft_contact_normal (array), Contact surface normal of soft contact point in world space, shape [soft_contact_max], vec3
636
+ soft_contact_tids (array), Thread indices of the soft contact points, shape [soft_contact_max], int
636
637
 
637
638
  rigid_contact_max (int): Maximum number of potential rigid body contact points to generate ignoring the `rigid_mesh_contact_max` limit.
638
639
  rigid_contact_max_limited (int): Maximum number of potential rigid body contact points to generate respecting the `rigid_mesh_contact_max` limit.
@@ -650,6 +651,12 @@ class Model:
650
651
  rigid_contact_thickness (array): Total contact thickness, shape [rigid_contact_max], float
651
652
  rigid_contact_shape0 (array): Index of shape 0 per contact, shape [rigid_contact_max], int
652
653
  rigid_contact_shape1 (array): Index of shape 1 per contact, shape [rigid_contact_max], int
654
+ rigid_contact_tids (array): Triangle indices of the contact points, shape [rigid_contact_max], int
655
+ rigid_contact_pairwise_counter (array): Pairwise counter for contact generation, shape [rigid_contact_max], int
656
+ rigid_contact_broad_shape0 (array): Broadphase shape index of shape 0 per contact, shape [rigid_contact_max], int
657
+ rigid_contact_broad_shape1 (array): Broadphase shape index of shape 1 per contact, shape [rigid_contact_max], int
658
+ rigid_contact_point_id (array): Contact point ID, shape [rigid_contact_max], int
659
+ rigid_contact_point_limit (array): Contact point limit, shape [rigid_contact_max], int
653
660
 
654
661
  ground (bool): Whether the ground plane and ground contacts are enabled
655
662
  ground_plane (array): Ground plane 3D normal and offset, shape [4], float
@@ -805,6 +812,7 @@ class Model:
805
812
  self.soft_contact_body_pos = None
806
813
  self.soft_contact_body_vel = None
807
814
  self.soft_contact_normal = None
815
+ self.soft_contact_tids = None
808
816
 
809
817
  self.rigid_contact_max = 0
810
818
  self.rigid_contact_max_limited = 0
@@ -822,6 +830,12 @@ class Model:
822
830
  self.rigid_contact_thickness = None
823
831
  self.rigid_contact_shape0 = None
824
832
  self.rigid_contact_shape1 = None
833
+ self.rigid_contact_tids = None
834
+ self.rigid_contact_pairwise_counter = None
835
+ self.rigid_contact_broad_shape0 = None
836
+ self.rigid_contact_broad_shape1 = None
837
+ self.rigid_contact_point_id = None
838
+ self.rigid_contact_point_limit = None
825
839
 
826
840
  # toggles ground contact for all shapes
827
841
  self.ground = True
@@ -3471,8 +3485,9 @@ class ModelBuilder:
3471
3485
  self.shape_shape_collision.append(has_shape_collision)
3472
3486
 
3473
3487
  (m, c, I) = compute_shape_mass(type, scale, src, density, is_solid, thickness)
3488
+ com_body = wp.transform_point(wp.transform(pos, rot), c)
3474
3489
 
3475
- self._update_body_mass(body, m, I, pos + c, rot)
3490
+ self._update_body_mass(body, m, I, com_body, rot)
3476
3491
  return shape
3477
3492
 
3478
3493
  # particles
@@ -4010,15 +4025,16 @@ class ModelBuilder:
4010
4025
  ) # opposite 0, opposite 1, vertex 0, vertex 1
4011
4026
 
4012
4027
  # skip constraints open edges
4013
- if e.f0 != -1 and e.f1 != -1:
4014
- spring_indices.add((min(e.o0, e.o1), max(e.o0, e.o1)))
4028
+ spring_indices.add((min(e.v0, e.v1), max(e.v0, e.v1)))
4029
+ if e.f0 != -1:
4015
4030
  spring_indices.add((min(e.o0, e.v0), max(e.o0, e.v0)))
4016
4031
  spring_indices.add((min(e.o0, e.v1), max(e.o0, e.v1)))
4017
-
4032
+ if e.f1 != -1:
4018
4033
  spring_indices.add((min(e.o1, e.v0), max(e.o1, e.v0)))
4019
4034
  spring_indices.add((min(e.o1, e.v1), max(e.o1, e.v1)))
4020
4035
 
4021
- spring_indices.add((min(e.v0, e.v1), max(e.v0, e.v1)))
4036
+ if e.f0 != -1 and e.f1 != -1:
4037
+ spring_indices.add((min(e.o0, e.o1), max(e.o0, e.o1)))
4022
4038
 
4023
4039
  if add_springs:
4024
4040
  for i, j in spring_indices:
@@ -4129,14 +4145,15 @@ class ModelBuilder:
4129
4145
  if add_springs:
4130
4146
  spring_indices = set()
4131
4147
  for i, j, k, l in edge_indices:
4132
- spring_indices.add((min(i, j), max(i, j)))
4133
- spring_indices.add((min(i, k), max(i, k)))
4134
- spring_indices.add((min(i, l), max(i, l)))
4135
-
4136
- spring_indices.add((min(j, k), max(j, k)))
4137
- spring_indices.add((min(j, l), max(j, l)))
4138
-
4139
4148
  spring_indices.add((min(k, l), max(k, l)))
4149
+ if i != -1:
4150
+ spring_indices.add((min(i, k), max(i, k)))
4151
+ spring_indices.add((min(i, l), max(i, l)))
4152
+ if j != -1:
4153
+ spring_indices.add((min(j, k), max(j, k)))
4154
+ spring_indices.add((min(j, l), max(j, l)))
4155
+ if i != -1 and j != -1:
4156
+ spring_indices.add((min(i, j), max(i, j)))
4140
4157
 
4141
4158
  for i, j in spring_indices:
4142
4159
  self.add_spring(i, j, spring_ke, spring_kd, control=0.0)
warp/sim/render.py CHANGED
@@ -273,6 +273,10 @@ def CreateSimRenderer(renderer):
273
273
  continue
274
274
  tf = joint_tf[i]
275
275
  body = int(joint_parent[i])
276
+ if body >= 0 and body < len(self.body_names):
277
+ body = self.body_names[body]
278
+ else:
279
+ body = None
276
280
  # if body == -1:
277
281
  # continue
278
282
  num_linear_axes = int(joint_axis_dim[i][0])
warp/stubs.py CHANGED
@@ -713,7 +713,7 @@ def quaternion(dtype: Float) -> Quaternion[Float]:
713
713
 
714
714
 
715
715
  @over
716
- def quaternion(x: Float, y: Float, z: Float, w: Float) -> Quaternion[Float]:
716
+ def quaternion(x: Float, y: Float, z: Float, w: Float, dtype: Scalar) -> Quaternion[Float]:
717
717
  """Create a quaternion using the supplied components (type inferred from component type)."""
718
718
  ...
719
719
 
@@ -59,9 +59,9 @@
59
59
  }
60
60
  defaultPrim = "World"
61
61
  endTimeCode = 100
62
+ framesPerSecond = 24
62
63
  metersPerUnit = 0.01
63
64
  startTimeCode = 0
64
- timeCodesPerSecond = 24
65
65
  upAxis = "Y"
66
66
  )
67
67