warp-lang 1.6.2__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.
- warp/__init__.py +7 -1
- warp/autograd.py +12 -2
- warp/bin/warp-clang.dll +0 -0
- warp/bin/warp.dll +0 -0
- warp/build.py +410 -0
- warp/build_dll.py +6 -14
- warp/builtins.py +463 -372
- warp/codegen.py +196 -124
- warp/config.py +42 -6
- warp/context.py +496 -271
- warp/dlpack.py +8 -6
- warp/examples/assets/nonuniform.usd +0 -0
- warp/examples/assets/nvidia_logo.png +0 -0
- warp/examples/benchmarks/benchmark_cloth.py +1 -1
- warp/examples/benchmarks/benchmark_tile_load_store.py +103 -0
- warp/examples/core/example_sample_mesh.py +300 -0
- warp/examples/distributed/example_jacobi_mpi.py +507 -0
- warp/examples/fem/example_apic_fluid.py +1 -1
- warp/examples/fem/example_burgers.py +2 -2
- warp/examples/fem/example_deformed_geometry.py +1 -1
- warp/examples/fem/example_distortion_energy.py +1 -1
- warp/examples/fem/example_magnetostatics.py +6 -6
- warp/examples/fem/utils.py +9 -3
- warp/examples/interop/example_jax_callable.py +116 -0
- warp/examples/interop/example_jax_ffi_callback.py +132 -0
- warp/examples/interop/example_jax_kernel.py +205 -0
- warp/examples/optim/example_fluid_checkpoint.py +497 -0
- warp/examples/tile/example_tile_matmul.py +2 -4
- warp/fem/__init__.py +11 -1
- warp/fem/adaptivity.py +4 -4
- warp/fem/field/field.py +11 -1
- warp/fem/field/nodal_field.py +56 -88
- warp/fem/field/virtual.py +62 -23
- warp/fem/geometry/adaptive_nanogrid.py +16 -13
- warp/fem/geometry/closest_point.py +1 -1
- warp/fem/geometry/deformed_geometry.py +5 -2
- warp/fem/geometry/geometry.py +5 -0
- warp/fem/geometry/grid_2d.py +12 -12
- warp/fem/geometry/grid_3d.py +12 -15
- warp/fem/geometry/hexmesh.py +5 -7
- warp/fem/geometry/nanogrid.py +9 -11
- warp/fem/geometry/quadmesh.py +13 -13
- warp/fem/geometry/tetmesh.py +3 -4
- warp/fem/geometry/trimesh.py +7 -20
- warp/fem/integrate.py +262 -93
- warp/fem/linalg.py +5 -5
- warp/fem/quadrature/pic_quadrature.py +37 -22
- warp/fem/quadrature/quadrature.py +194 -25
- warp/fem/space/__init__.py +1 -1
- warp/fem/space/basis_function_space.py +4 -2
- warp/fem/space/basis_space.py +25 -18
- warp/fem/space/hexmesh_function_space.py +2 -2
- warp/fem/space/partition.py +6 -2
- warp/fem/space/quadmesh_function_space.py +8 -8
- warp/fem/space/shape/cube_shape_function.py +23 -23
- warp/fem/space/shape/square_shape_function.py +12 -12
- warp/fem/space/shape/triangle_shape_function.py +1 -1
- warp/fem/space/tetmesh_function_space.py +3 -3
- warp/fem/space/trimesh_function_space.py +2 -2
- warp/fem/utils.py +12 -6
- warp/jax.py +14 -1
- warp/jax_experimental/__init__.py +16 -0
- warp/{jax_experimental.py → jax_experimental/custom_call.py} +28 -29
- warp/jax_experimental/ffi.py +702 -0
- warp/jax_experimental/xla_ffi.py +602 -0
- warp/math.py +89 -0
- warp/native/array.h +13 -0
- warp/native/builtin.h +29 -3
- warp/native/bvh.cpp +3 -1
- warp/native/bvh.cu +42 -14
- warp/native/bvh.h +2 -1
- warp/native/clang/clang.cpp +30 -3
- warp/native/cuda_util.cpp +14 -0
- warp/native/cuda_util.h +2 -0
- warp/native/exports.h +68 -63
- warp/native/intersect.h +26 -26
- warp/native/intersect_adj.h +33 -33
- warp/native/marching.cu +1 -1
- warp/native/mat.h +513 -9
- warp/native/mesh.h +10 -10
- warp/native/quat.h +99 -11
- warp/native/rand.h +6 -0
- warp/native/sort.cpp +122 -59
- warp/native/sort.cu +152 -15
- warp/native/sort.h +8 -1
- warp/native/sparse.cpp +43 -22
- warp/native/sparse.cu +52 -17
- warp/native/svd.h +116 -0
- warp/native/tile.h +312 -116
- warp/native/tile_reduce.h +46 -3
- warp/native/vec.h +68 -7
- warp/native/volume.cpp +85 -113
- warp/native/volume_builder.cu +25 -10
- warp/native/volume_builder.h +6 -0
- warp/native/warp.cpp +5 -6
- warp/native/warp.cu +100 -11
- warp/native/warp.h +19 -10
- warp/optim/linear.py +10 -10
- warp/render/render_opengl.py +19 -17
- warp/render/render_usd.py +93 -3
- warp/sim/articulation.py +4 -4
- warp/sim/collide.py +32 -19
- warp/sim/import_mjcf.py +449 -155
- warp/sim/import_urdf.py +32 -12
- warp/sim/inertia.py +189 -156
- warp/sim/integrator_euler.py +8 -5
- warp/sim/integrator_featherstone.py +3 -10
- warp/sim/integrator_vbd.py +207 -2
- warp/sim/integrator_xpbd.py +8 -5
- warp/sim/model.py +71 -25
- warp/sim/render.py +4 -0
- warp/sim/utils.py +2 -2
- warp/sparse.py +642 -555
- warp/stubs.py +217 -20
- warp/tests/__main__.py +0 -15
- warp/tests/assets/torus.usda +1 -1
- warp/tests/cuda/__init__.py +0 -0
- warp/tests/{test_mempool.py → cuda/test_mempool.py} +39 -0
- warp/tests/{test_streams.py → cuda/test_streams.py} +71 -0
- warp/tests/geometry/__init__.py +0 -0
- warp/tests/{test_mesh_query_point.py → geometry/test_mesh_query_point.py} +66 -63
- warp/tests/{test_mesh_query_ray.py → geometry/test_mesh_query_ray.py} +1 -1
- warp/tests/{test_volume.py → geometry/test_volume.py} +41 -6
- warp/tests/interop/__init__.py +0 -0
- warp/tests/{test_dlpack.py → interop/test_dlpack.py} +28 -5
- warp/tests/sim/__init__.py +0 -0
- warp/tests/{disabled_kinematics.py → sim/disabled_kinematics.py} +9 -10
- warp/tests/{test_collision.py → sim/test_collision.py} +236 -205
- warp/tests/sim/test_inertia.py +161 -0
- warp/tests/{test_model.py → sim/test_model.py} +40 -0
- warp/tests/{flaky_test_sim_grad.py → sim/test_sim_grad.py} +4 -0
- warp/tests/{test_sim_kinematics.py → sim/test_sim_kinematics.py} +2 -1
- warp/tests/sim/test_vbd.py +597 -0
- warp/tests/sim/test_xpbd.py +399 -0
- warp/tests/test_bool.py +1 -1
- warp/tests/test_codegen.py +24 -3
- warp/tests/test_examples.py +40 -38
- warp/tests/test_fem.py +98 -14
- warp/tests/test_linear_solvers.py +0 -11
- warp/tests/test_mat.py +577 -156
- warp/tests/test_mat_scalar_ops.py +4 -4
- warp/tests/test_overwrite.py +0 -60
- warp/tests/test_quat.py +356 -151
- warp/tests/test_rand.py +44 -37
- warp/tests/test_sparse.py +47 -6
- warp/tests/test_spatial.py +75 -0
- warp/tests/test_static.py +1 -1
- warp/tests/test_utils.py +84 -4
- warp/tests/test_vec.py +336 -178
- warp/tests/tile/__init__.py +0 -0
- warp/tests/{test_tile.py → tile/test_tile.py} +136 -51
- warp/tests/{test_tile_load.py → tile/test_tile_load.py} +98 -1
- warp/tests/{test_tile_mathdx.py → tile/test_tile_mathdx.py} +9 -6
- warp/tests/{test_tile_mlp.py → tile/test_tile_mlp.py} +25 -14
- warp/tests/{test_tile_reduce.py → tile/test_tile_reduce.py} +60 -1
- warp/tests/{test_tile_view.py → tile/test_tile_view.py} +1 -1
- warp/tests/unittest_serial.py +1 -0
- warp/tests/unittest_suites.py +45 -62
- warp/tests/unittest_utils.py +2 -1
- warp/thirdparty/unittest_parallel.py +3 -1
- warp/types.py +175 -666
- warp/utils.py +137 -72
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.1.dist-info}/METADATA +46 -12
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.1.dist-info}/RECORD +184 -171
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.1.dist-info}/WHEEL +1 -1
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.1.dist-info/licenses}/LICENSE.md +0 -26
- warp/examples/optim/example_walker.py +0 -317
- warp/native/cutlass_gemm.cpp +0 -43
- warp/native/cutlass_gemm.cu +0 -382
- warp/tests/test_matmul.py +0 -511
- warp/tests/test_matmul_lite.py +0 -411
- warp/tests/test_vbd.py +0 -386
- warp/tests/unused_test_misc.py +0 -77
- /warp/tests/{test_async.py → cuda/test_async.py} +0 -0
- /warp/tests/{test_ipc.py → cuda/test_ipc.py} +0 -0
- /warp/tests/{test_multigpu.py → cuda/test_multigpu.py} +0 -0
- /warp/tests/{test_peer.py → cuda/test_peer.py} +0 -0
- /warp/tests/{test_pinned.py → cuda/test_pinned.py} +0 -0
- /warp/tests/{test_bvh.py → geometry/test_bvh.py} +0 -0
- /warp/tests/{test_hash_grid.py → geometry/test_hash_grid.py} +0 -0
- /warp/tests/{test_marching_cubes.py → geometry/test_marching_cubes.py} +0 -0
- /warp/tests/{test_mesh.py → geometry/test_mesh.py} +0 -0
- /warp/tests/{test_mesh_query_aabb.py → geometry/test_mesh_query_aabb.py} +0 -0
- /warp/tests/{test_volume_write.py → geometry/test_volume_write.py} +0 -0
- /warp/tests/{test_jax.py → interop/test_jax.py} +0 -0
- /warp/tests/{test_paddle.py → interop/test_paddle.py} +0 -0
- /warp/tests/{test_torch.py → interop/test_torch.py} +0 -0
- /warp/tests/{test_coloring.py → sim/test_coloring.py} +0 -0
- /warp/tests/{test_sim_grad_bounce_linear.py → sim/test_sim_grad_bounce_linear.py} +0 -0
- /warp/tests/{test_tile_shared_memory.py → tile/test_tile_shared_memory.py} +0 -0
- {warp_lang-1.6.2.dist-info → warp_lang-1.7.1.dist-info}/top_level.txt +0 -0
|
@@ -18,7 +18,12 @@ import unittest
|
|
|
18
18
|
import warp as wp
|
|
19
19
|
import warp.examples
|
|
20
20
|
import warp.sim
|
|
21
|
-
from warp.sim.collide import
|
|
21
|
+
from warp.sim.collide import (
|
|
22
|
+
TriMeshCollisionDetector,
|
|
23
|
+
init_triangle_collision_data_kernel,
|
|
24
|
+
triangle_closest_point,
|
|
25
|
+
vertex_adjacent_to_triangle,
|
|
26
|
+
)
|
|
22
27
|
from warp.sim.integrator_euler import eval_triangles_contact
|
|
23
28
|
from warp.tests.unittest_utils import *
|
|
24
29
|
|
|
@@ -260,229 +265,205 @@ def validate_edge_collisions(
|
|
|
260
265
|
wp.expect_eq(dist >= min_dist, True)
|
|
261
266
|
|
|
262
267
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
self.device = device
|
|
268
|
+
def init_model(vs, fs, device):
|
|
269
|
+
vertices = [wp.vec3(v) for v in vs]
|
|
266
270
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
271
|
+
builder = wp.sim.ModelBuilder()
|
|
272
|
+
builder.add_cloth_mesh(
|
|
273
|
+
pos=wp.vec3(0.0, 200.0, 0.0),
|
|
274
|
+
rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
|
|
275
|
+
scale=1.0,
|
|
276
|
+
vertices=vertices,
|
|
277
|
+
indices=fs,
|
|
278
|
+
vel=wp.vec3(0.0, 0.0, 0.0),
|
|
279
|
+
density=0.02,
|
|
280
|
+
tri_ke=0,
|
|
281
|
+
tri_ka=0,
|
|
282
|
+
tri_kd=0,
|
|
283
|
+
)
|
|
284
|
+
model = builder.finalize(device=device)
|
|
270
285
|
|
|
271
|
-
|
|
272
|
-
builder.add_cloth_mesh(
|
|
273
|
-
pos=wp.vec3(0.0, 200.0, 0.0),
|
|
274
|
-
rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), 0.0),
|
|
275
|
-
scale=1.0,
|
|
276
|
-
vertices=vertices,
|
|
277
|
-
indices=fs,
|
|
278
|
-
vel=wp.vec3(0.0, 0.0, 0.0),
|
|
279
|
-
density=0.02,
|
|
280
|
-
tri_ke=0,
|
|
281
|
-
tri_ka=0,
|
|
282
|
-
tri_kd=0,
|
|
283
|
-
)
|
|
284
|
-
self.model = builder.finalize(device=self.device)
|
|
285
|
-
|
|
286
|
-
self.collision_detector = TriMeshCollisionDetector(model=self.model)
|
|
287
|
-
|
|
288
|
-
def run_vertex_triangle_test(self):
|
|
289
|
-
rs = [1e-2, 2e-2, 5e-2, 1e-1]
|
|
290
|
-
for query_radius in rs:
|
|
291
|
-
self.collision_detector.vertex_triangle_collision_detection(query_radius)
|
|
292
|
-
vertex_colliding_triangles_count_1 = self.collision_detector.vertex_colliding_triangles_count.numpy()
|
|
293
|
-
vertex_min_dis_1 = self.collision_detector.vertex_colliding_triangles_min_dist.numpy()
|
|
294
|
-
|
|
295
|
-
triangle_colliding_vertices_count_1 = self.collision_detector.triangle_colliding_vertices_count.numpy()
|
|
296
|
-
triangle_min_dis_1 = self.collision_detector.triangle_colliding_vertices_min_dist.numpy()
|
|
297
|
-
|
|
298
|
-
wp.launch(
|
|
299
|
-
kernel=init_triangle_collision_data_kernel,
|
|
300
|
-
inputs=[
|
|
301
|
-
query_radius,
|
|
302
|
-
self.collision_detector.triangle_colliding_vertices_count,
|
|
303
|
-
self.collision_detector.triangle_colliding_vertices_min_dist,
|
|
304
|
-
self.collision_detector.resize_flags,
|
|
305
|
-
],
|
|
306
|
-
dim=self.model.tri_count,
|
|
307
|
-
device=self.model.device,
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
wp.launch(
|
|
311
|
-
kernel=vertex_triangle_collision_detection_brute_force,
|
|
312
|
-
inputs=[
|
|
313
|
-
query_radius,
|
|
314
|
-
self.collision_detector.bvh_tris.id,
|
|
315
|
-
self.collision_detector.model.particle_q,
|
|
316
|
-
self.collision_detector.model.tri_indices,
|
|
317
|
-
self.collision_detector.vertex_colliding_triangles,
|
|
318
|
-
self.collision_detector.vertex_colliding_triangles_count,
|
|
319
|
-
self.collision_detector.vertex_colliding_triangles_offsets,
|
|
320
|
-
self.collision_detector.vertex_colliding_triangles_buffer_sizes,
|
|
321
|
-
self.collision_detector.vertex_colliding_triangles_min_dist,
|
|
322
|
-
self.collision_detector.triangle_colliding_vertices,
|
|
323
|
-
self.collision_detector.triangle_colliding_vertices_count,
|
|
324
|
-
self.collision_detector.triangle_colliding_vertices_offsets,
|
|
325
|
-
self.collision_detector.triangle_colliding_vertices_buffer_sizes,
|
|
326
|
-
self.collision_detector.triangle_colliding_vertices_min_dist,
|
|
327
|
-
self.collision_detector.resize_flags,
|
|
328
|
-
],
|
|
329
|
-
dim=self.model.particle_count,
|
|
330
|
-
device=self.model.device,
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
vertex_colliding_triangles_count_2 = self.collision_detector.vertex_colliding_triangles_count.numpy()
|
|
334
|
-
vertex_min_dis_2 = self.collision_detector.vertex_colliding_triangles_min_dist.numpy()
|
|
335
|
-
|
|
336
|
-
triangle_colliding_vertices_count_2 = self.collision_detector.triangle_colliding_vertices_count.numpy()
|
|
337
|
-
triangle_min_dis_2 = self.collision_detector.triangle_colliding_vertices_min_dist.numpy()
|
|
338
|
-
|
|
339
|
-
assert (vertex_colliding_triangles_count_2 == vertex_colliding_triangles_count_1).all()
|
|
340
|
-
assert (triangle_min_dis_2 == triangle_min_dis_1).all()
|
|
341
|
-
assert (triangle_colliding_vertices_count_2 == triangle_colliding_vertices_count_1).all()
|
|
342
|
-
assert (vertex_min_dis_2 == vertex_min_dis_1).all()
|
|
343
|
-
|
|
344
|
-
wp.launch(
|
|
345
|
-
kernel=validate_vertex_collisions,
|
|
346
|
-
inputs=[
|
|
347
|
-
query_radius,
|
|
348
|
-
self.collision_detector.bvh_tris.id,
|
|
349
|
-
self.collision_detector.model.particle_q,
|
|
350
|
-
self.collision_detector.model.tri_indices,
|
|
351
|
-
self.collision_detector.vertex_colliding_triangles,
|
|
352
|
-
self.collision_detector.vertex_colliding_triangles_count,
|
|
353
|
-
self.collision_detector.vertex_colliding_triangles_offsets,
|
|
354
|
-
self.collision_detector.vertex_colliding_triangles_buffer_sizes,
|
|
355
|
-
self.collision_detector.vertex_colliding_triangles_min_dist,
|
|
356
|
-
self.collision_detector.resize_flags,
|
|
357
|
-
],
|
|
358
|
-
dim=self.model.particle_count,
|
|
359
|
-
device=self.model.device,
|
|
360
|
-
)
|
|
361
|
-
|
|
362
|
-
wp.launch(
|
|
363
|
-
kernel=validate_triangle_collisions,
|
|
364
|
-
inputs=[
|
|
365
|
-
query_radius,
|
|
366
|
-
self.collision_detector.bvh_tris.id,
|
|
367
|
-
self.collision_detector.model.particle_q,
|
|
368
|
-
self.collision_detector.model.tri_indices,
|
|
369
|
-
self.collision_detector.triangle_colliding_vertices,
|
|
370
|
-
self.collision_detector.triangle_colliding_vertices_count,
|
|
371
|
-
self.collision_detector.triangle_colliding_vertices_offsets,
|
|
372
|
-
self.collision_detector.triangle_colliding_vertices_buffer_sizes,
|
|
373
|
-
self.collision_detector.triangle_colliding_vertices_min_dist,
|
|
374
|
-
self.collision_detector.resize_flags,
|
|
375
|
-
],
|
|
376
|
-
dim=self.model.tri_count,
|
|
377
|
-
device=self.model.device,
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
def run_edge_edge_test(self):
|
|
381
|
-
rs = [1e-2, 2e-2, 5e-2, 1e-1]
|
|
382
|
-
edge_edge_parallel_epsilon = 1e-5
|
|
383
|
-
for query_radius in rs:
|
|
384
|
-
self.collision_detector.edge_edge_collision_detection(query_radius)
|
|
385
|
-
edge_colliding_edges_count_1 = self.collision_detector.edge_colliding_edges_count.numpy()
|
|
386
|
-
edge_min_dist_1 = self.collision_detector.edge_colliding_edges_min_dist.numpy()
|
|
387
|
-
|
|
388
|
-
print(edge_colliding_edges_count_1)
|
|
389
|
-
|
|
390
|
-
wp.launch(
|
|
391
|
-
kernel=edge_edge_collision_detection_brute_force,
|
|
392
|
-
inputs=[
|
|
393
|
-
query_radius,
|
|
394
|
-
self.collision_detector.bvh_edges.id,
|
|
395
|
-
self.collision_detector.model.particle_q,
|
|
396
|
-
self.collision_detector.model.edge_indices,
|
|
397
|
-
self.collision_detector.edge_colliding_edges_offsets,
|
|
398
|
-
self.collision_detector.edge_colliding_edges_buffer_sizes,
|
|
399
|
-
edge_edge_parallel_epsilon,
|
|
400
|
-
],
|
|
401
|
-
outputs=[
|
|
402
|
-
self.collision_detector.edge_colliding_edges,
|
|
403
|
-
self.collision_detector.edge_colliding_edges_count,
|
|
404
|
-
self.collision_detector.edge_colliding_edges_min_dist,
|
|
405
|
-
self.collision_detector.resize_flags,
|
|
406
|
-
],
|
|
407
|
-
dim=self.model.edge_count,
|
|
408
|
-
device=self.model.device,
|
|
409
|
-
)
|
|
410
|
-
|
|
411
|
-
edge_colliding_edges_count_2 = self.collision_detector.edge_colliding_edges_count.numpy()
|
|
412
|
-
edge_min_dist_2 = self.collision_detector.edge_colliding_edges_min_dist.numpy()
|
|
413
|
-
|
|
414
|
-
assert (edge_colliding_edges_count_2 == edge_colliding_edges_count_1).all()
|
|
415
|
-
assert (edge_min_dist_1 == edge_min_dist_2).all()
|
|
416
|
-
|
|
417
|
-
wp.launch(
|
|
418
|
-
kernel=validate_edge_collisions,
|
|
419
|
-
inputs=[
|
|
420
|
-
query_radius,
|
|
421
|
-
self.collision_detector.bvh_edges.id,
|
|
422
|
-
self.collision_detector.model.particle_q,
|
|
423
|
-
self.collision_detector.model.edge_indices,
|
|
424
|
-
self.collision_detector.edge_colliding_edges_offsets,
|
|
425
|
-
self.collision_detector.edge_colliding_edges_buffer_sizes,
|
|
426
|
-
edge_edge_parallel_epsilon,
|
|
427
|
-
],
|
|
428
|
-
outputs=[
|
|
429
|
-
self.collision_detector.edge_colliding_edges,
|
|
430
|
-
self.collision_detector.edge_colliding_edges_count,
|
|
431
|
-
self.collision_detector.edge_colliding_edges_min_dist,
|
|
432
|
-
self.collision_detector.resize_flags,
|
|
433
|
-
],
|
|
434
|
-
dim=self.model.particle_count,
|
|
435
|
-
device=self.model.device,
|
|
436
|
-
)
|
|
437
|
-
|
|
438
|
-
def set_points_fixed(self, model, fixed_particles):
|
|
439
|
-
if len(fixed_particles):
|
|
440
|
-
flags = model.particle_flags.numpy()
|
|
441
|
-
for fixed_vertex_id in fixed_particles:
|
|
442
|
-
flags[fixed_vertex_id] = wp.uint32(int(flags[fixed_vertex_id]) & ~int(PARTICLE_FLAG_ACTIVE))
|
|
443
|
-
|
|
444
|
-
model.particle_flags = wp.array(flags, device=model.device)
|
|
286
|
+
collision_detector = TriMeshCollisionDetector(model=model)
|
|
445
287
|
|
|
288
|
+
return model, collision_detector
|
|
446
289
|
|
|
447
|
-
|
|
448
|
-
def
|
|
290
|
+
|
|
291
|
+
def get_data():
|
|
449
292
|
from pxr import Usd, UsdGeom
|
|
450
293
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
294
|
+
usd_stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "bunny.usd"))
|
|
295
|
+
usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/root/bunny"))
|
|
296
|
+
|
|
297
|
+
vertices = np.array(usd_geom.GetPointsAttr().Get())
|
|
298
|
+
faces = np.array(usd_geom.GetFaceVertexIndicesAttr().Get())
|
|
454
299
|
|
|
455
|
-
|
|
456
|
-
faces = np.array(usd_geom.GetFaceVertexIndicesAttr().Get())
|
|
300
|
+
return vertices, faces
|
|
457
301
|
|
|
458
|
-
return vertices, faces
|
|
459
302
|
|
|
303
|
+
@unittest.skipUnless(USD_AVAILABLE, "Requires usd-core")
|
|
304
|
+
def test_vertex_triangle_collision(test, device):
|
|
460
305
|
vertices, faces = get_data()
|
|
461
306
|
|
|
462
|
-
|
|
463
|
-
sim.run_vertex_triangle_test()
|
|
307
|
+
model, collision_detector = init_model(vertices, faces, device)
|
|
464
308
|
|
|
309
|
+
rs = [1e-2, 2e-2, 5e-2, 1e-1]
|
|
465
310
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
311
|
+
for query_radius in rs:
|
|
312
|
+
collision_detector.vertex_triangle_collision_detection(query_radius)
|
|
313
|
+
vertex_colliding_triangles_count_1 = collision_detector.vertex_colliding_triangles_count.numpy()
|
|
314
|
+
vertex_min_dis_1 = collision_detector.vertex_colliding_triangles_min_dist.numpy()
|
|
469
315
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/root/bunny"))
|
|
316
|
+
triangle_colliding_vertices_count_1 = collision_detector.triangle_colliding_vertices_count.numpy()
|
|
317
|
+
triangle_min_dis_1 = collision_detector.triangle_colliding_vertices_min_dist.numpy()
|
|
473
318
|
|
|
474
|
-
|
|
475
|
-
|
|
319
|
+
wp.launch(
|
|
320
|
+
kernel=init_triangle_collision_data_kernel,
|
|
321
|
+
inputs=[
|
|
322
|
+
query_radius,
|
|
323
|
+
collision_detector.triangle_colliding_vertices_count,
|
|
324
|
+
collision_detector.triangle_colliding_vertices_min_dist,
|
|
325
|
+
collision_detector.resize_flags,
|
|
326
|
+
],
|
|
327
|
+
dim=model.tri_count,
|
|
328
|
+
device=device,
|
|
329
|
+
)
|
|
476
330
|
|
|
477
|
-
|
|
331
|
+
wp.launch(
|
|
332
|
+
kernel=vertex_triangle_collision_detection_brute_force,
|
|
333
|
+
inputs=[
|
|
334
|
+
query_radius,
|
|
335
|
+
collision_detector.bvh_tris.id,
|
|
336
|
+
collision_detector.model.particle_q,
|
|
337
|
+
collision_detector.model.tri_indices,
|
|
338
|
+
collision_detector.vertex_colliding_triangles,
|
|
339
|
+
collision_detector.vertex_colliding_triangles_count,
|
|
340
|
+
collision_detector.vertex_colliding_triangles_offsets,
|
|
341
|
+
collision_detector.vertex_colliding_triangles_buffer_sizes,
|
|
342
|
+
collision_detector.vertex_colliding_triangles_min_dist,
|
|
343
|
+
collision_detector.triangle_colliding_vertices,
|
|
344
|
+
collision_detector.triangle_colliding_vertices_count,
|
|
345
|
+
collision_detector.triangle_colliding_vertices_offsets,
|
|
346
|
+
collision_detector.triangle_colliding_vertices_buffer_sizes,
|
|
347
|
+
collision_detector.triangle_colliding_vertices_min_dist,
|
|
348
|
+
collision_detector.resize_flags,
|
|
349
|
+
],
|
|
350
|
+
dim=model.particle_count,
|
|
351
|
+
device=device,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
vertex_colliding_triangles_count_2 = collision_detector.vertex_colliding_triangles_count.numpy()
|
|
355
|
+
vertex_min_dis_2 = collision_detector.vertex_colliding_triangles_min_dist.numpy()
|
|
356
|
+
|
|
357
|
+
triangle_colliding_vertices_count_2 = collision_detector.triangle_colliding_vertices_count.numpy()
|
|
358
|
+
triangle_min_dis_2 = collision_detector.triangle_colliding_vertices_min_dist.numpy()
|
|
359
|
+
|
|
360
|
+
assert_np_equal(vertex_colliding_triangles_count_2, vertex_colliding_triangles_count_1)
|
|
361
|
+
assert_np_equal(triangle_min_dis_2, triangle_min_dis_1)
|
|
362
|
+
assert_np_equal(triangle_colliding_vertices_count_2, triangle_colliding_vertices_count_1)
|
|
363
|
+
assert_np_equal(vertex_min_dis_2, vertex_min_dis_1)
|
|
364
|
+
|
|
365
|
+
wp.launch(
|
|
366
|
+
kernel=validate_vertex_collisions,
|
|
367
|
+
inputs=[
|
|
368
|
+
query_radius,
|
|
369
|
+
collision_detector.bvh_tris.id,
|
|
370
|
+
collision_detector.model.particle_q,
|
|
371
|
+
collision_detector.model.tri_indices,
|
|
372
|
+
collision_detector.vertex_colliding_triangles,
|
|
373
|
+
collision_detector.vertex_colliding_triangles_count,
|
|
374
|
+
collision_detector.vertex_colliding_triangles_offsets,
|
|
375
|
+
collision_detector.vertex_colliding_triangles_buffer_sizes,
|
|
376
|
+
collision_detector.vertex_colliding_triangles_min_dist,
|
|
377
|
+
collision_detector.resize_flags,
|
|
378
|
+
],
|
|
379
|
+
dim=model.particle_count,
|
|
380
|
+
device=device,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
wp.launch(
|
|
384
|
+
kernel=validate_triangle_collisions,
|
|
385
|
+
inputs=[
|
|
386
|
+
query_radius,
|
|
387
|
+
collision_detector.bvh_tris.id,
|
|
388
|
+
collision_detector.model.particle_q,
|
|
389
|
+
collision_detector.model.tri_indices,
|
|
390
|
+
collision_detector.triangle_colliding_vertices,
|
|
391
|
+
collision_detector.triangle_colliding_vertices_count,
|
|
392
|
+
collision_detector.triangle_colliding_vertices_offsets,
|
|
393
|
+
collision_detector.triangle_colliding_vertices_buffer_sizes,
|
|
394
|
+
collision_detector.triangle_colliding_vertices_min_dist,
|
|
395
|
+
collision_detector.resize_flags,
|
|
396
|
+
],
|
|
397
|
+
dim=model.tri_count,
|
|
398
|
+
device=device,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
wp.synchronize_device(device)
|
|
478
402
|
|
|
403
|
+
|
|
404
|
+
@unittest.skipUnless(USD_AVAILABLE, "Requires usd-core")
|
|
405
|
+
def test_edge_edge_collision(test, device):
|
|
479
406
|
vertices, faces = get_data()
|
|
480
407
|
|
|
481
|
-
|
|
482
|
-
|
|
408
|
+
model, collision_detector = init_model(vertices, faces, device)
|
|
409
|
+
|
|
410
|
+
rs = [1e-2, 2e-2, 5e-2, 1e-1]
|
|
411
|
+
edge_edge_parallel_epsilon = 1e-5
|
|
412
|
+
|
|
413
|
+
for query_radius in rs:
|
|
414
|
+
collision_detector.edge_edge_collision_detection(query_radius)
|
|
415
|
+
edge_colliding_edges_count_1 = collision_detector.edge_colliding_edges_count.numpy()
|
|
416
|
+
edge_min_dist_1 = collision_detector.edge_colliding_edges_min_dist.numpy()
|
|
417
|
+
|
|
418
|
+
wp.launch(
|
|
419
|
+
kernel=edge_edge_collision_detection_brute_force,
|
|
420
|
+
inputs=[
|
|
421
|
+
query_radius,
|
|
422
|
+
collision_detector.bvh_edges.id,
|
|
423
|
+
collision_detector.model.particle_q,
|
|
424
|
+
collision_detector.model.edge_indices,
|
|
425
|
+
collision_detector.edge_colliding_edges_offsets,
|
|
426
|
+
collision_detector.edge_colliding_edges_buffer_sizes,
|
|
427
|
+
edge_edge_parallel_epsilon,
|
|
428
|
+
],
|
|
429
|
+
outputs=[
|
|
430
|
+
collision_detector.edge_colliding_edges,
|
|
431
|
+
collision_detector.edge_colliding_edges_count,
|
|
432
|
+
collision_detector.edge_colliding_edges_min_dist,
|
|
433
|
+
collision_detector.resize_flags,
|
|
434
|
+
],
|
|
435
|
+
dim=model.edge_count,
|
|
436
|
+
device=device,
|
|
437
|
+
)
|
|
483
438
|
|
|
439
|
+
edge_colliding_edges_count_2 = collision_detector.edge_colliding_edges_count.numpy()
|
|
440
|
+
edge_min_dist_2 = collision_detector.edge_colliding_edges_min_dist.numpy()
|
|
441
|
+
|
|
442
|
+
assert_np_equal(edge_colliding_edges_count_2, edge_colliding_edges_count_1)
|
|
443
|
+
assert_np_equal(edge_min_dist_2, edge_min_dist_1)
|
|
444
|
+
|
|
445
|
+
wp.launch(
|
|
446
|
+
kernel=validate_edge_collisions,
|
|
447
|
+
inputs=[
|
|
448
|
+
query_radius,
|
|
449
|
+
collision_detector.bvh_edges.id,
|
|
450
|
+
collision_detector.model.particle_q,
|
|
451
|
+
collision_detector.model.edge_indices,
|
|
452
|
+
collision_detector.edge_colliding_edges_offsets,
|
|
453
|
+
collision_detector.edge_colliding_edges_buffer_sizes,
|
|
454
|
+
edge_edge_parallel_epsilon,
|
|
455
|
+
],
|
|
456
|
+
outputs=[
|
|
457
|
+
collision_detector.edge_colliding_edges,
|
|
458
|
+
collision_detector.edge_colliding_edges_count,
|
|
459
|
+
collision_detector.edge_colliding_edges_min_dist,
|
|
460
|
+
collision_detector.resize_flags,
|
|
461
|
+
],
|
|
462
|
+
dim=model.particle_count,
|
|
463
|
+
device=device,
|
|
464
|
+
)
|
|
484
465
|
|
|
485
|
-
|
|
466
|
+
wp.synchronize_device(device)
|
|
486
467
|
|
|
487
468
|
|
|
488
469
|
def test_particle_collision(test, device):
|
|
@@ -591,14 +572,64 @@ def test_particle_collision(test, device):
|
|
|
591
572
|
test.assertTrue((np.linalg.norm(particle_f_2.numpy(), axis=1) == 0).all())
|
|
592
573
|
|
|
593
574
|
|
|
575
|
+
def test_mesh_ground_collision_index(test, device):
|
|
576
|
+
# create a mesh with 1 triangle for testing
|
|
577
|
+
vertices = np.array(
|
|
578
|
+
[
|
|
579
|
+
[0.0, 0.0, 0.0],
|
|
580
|
+
[1.0, 1.0, 0.0],
|
|
581
|
+
[0.5, 2.0, 0.0],
|
|
582
|
+
]
|
|
583
|
+
)
|
|
584
|
+
mesh = wp.sim.Mesh(vertices=vertices, indices=[0, 1, 2])
|
|
585
|
+
builder = wp.sim.ModelBuilder()
|
|
586
|
+
# create body with nonzero mass to ensure it is not static
|
|
587
|
+
# and contact points will be computed
|
|
588
|
+
b = builder.add_body(m=1.0)
|
|
589
|
+
builder.add_shape_mesh(
|
|
590
|
+
body=b,
|
|
591
|
+
mesh=mesh,
|
|
592
|
+
has_shape_collision=False,
|
|
593
|
+
)
|
|
594
|
+
# add another mesh that is not in contact
|
|
595
|
+
b2 = builder.add_body(m=1.0, origin=wp.transform((0.0, 3.0, 0.0), wp.quat_identity()))
|
|
596
|
+
builder.add_shape_mesh(
|
|
597
|
+
body=b2,
|
|
598
|
+
mesh=mesh,
|
|
599
|
+
has_shape_collision=False,
|
|
600
|
+
)
|
|
601
|
+
model = builder.finalize(device=device)
|
|
602
|
+
test.assertEqual(model.rigid_contact_max, 6)
|
|
603
|
+
test.assertEqual(model.shape_contact_pair_count, 0)
|
|
604
|
+
test.assertEqual(model.shape_ground_contact_pair_count, 2)
|
|
605
|
+
model.ground = True
|
|
606
|
+
# ensure all the mesh vertices will be within the contact margin
|
|
607
|
+
model.rigid_contact_margin = 2.0
|
|
608
|
+
state = model.state()
|
|
609
|
+
wp.sim.collide(model, state)
|
|
610
|
+
test.assertEqual(model.rigid_contact_count.numpy()[0], 3)
|
|
611
|
+
tids = model.rigid_contact_tids.list()
|
|
612
|
+
test.assertEqual(sorted(tids), [-1, -1, -1, 0, 1, 2])
|
|
613
|
+
tids = [t for t in tids if t != -1]
|
|
614
|
+
# retrieve the mesh vertices from the contact thread indices
|
|
615
|
+
assert_np_equal(model.rigid_contact_point0.numpy()[:3], vertices[tids])
|
|
616
|
+
assert_np_equal(model.rigid_contact_point1.numpy()[:3, 0], vertices[tids, 0])
|
|
617
|
+
assert_np_equal(model.rigid_contact_point1.numpy()[:3, 1:], np.zeros((3, 2)))
|
|
618
|
+
assert_np_equal(model.rigid_contact_normal.numpy()[:3], np.tile([0.0, 1.0, 0.0], (3, 1)))
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
devices = get_test_devices(mode="basic")
|
|
622
|
+
|
|
623
|
+
|
|
594
624
|
class TestCollision(unittest.TestCase):
|
|
595
625
|
pass
|
|
596
626
|
|
|
597
627
|
|
|
598
628
|
add_function_test(TestCollision, "test_vertex_triangle_collision", test_vertex_triangle_collision, devices=devices)
|
|
599
|
-
add_function_test(TestCollision, "test_edge_edge_collision",
|
|
629
|
+
add_function_test(TestCollision, "test_edge_edge_collision", test_edge_edge_collision, devices=devices)
|
|
600
630
|
add_function_test(TestCollision, "test_particle_collision", test_particle_collision, devices=devices)
|
|
631
|
+
add_function_test(TestCollision, "test_mesh_ground_collision_index", test_mesh_ground_collision_index, devices=devices)
|
|
601
632
|
|
|
602
633
|
if __name__ == "__main__":
|
|
603
634
|
wp.clear_kernel_cache()
|
|
604
|
-
unittest.main(verbosity=2)
|
|
635
|
+
unittest.main(verbosity=2, failfast=True)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import unittest
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
import warp as wp
|
|
21
|
+
from warp.render.render_opengl import OpenGLRenderer
|
|
22
|
+
from warp.sim import ModelBuilder
|
|
23
|
+
from warp.sim.inertia import (
|
|
24
|
+
compute_box_inertia,
|
|
25
|
+
compute_mesh_inertia,
|
|
26
|
+
compute_sphere_inertia,
|
|
27
|
+
)
|
|
28
|
+
from warp.tests.unittest_utils import assert_np_equal
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestInertia(unittest.TestCase):
|
|
32
|
+
def test_cube_mesh_inertia(self):
|
|
33
|
+
# Unit cube
|
|
34
|
+
vertices = [
|
|
35
|
+
[1.0, 0.0, 0.0],
|
|
36
|
+
[1.0, 0.0, 1.0],
|
|
37
|
+
[0.0, 0.0, 1.0],
|
|
38
|
+
[0.0, 0.0, 0.0],
|
|
39
|
+
[1.0, 1.0, 0.0],
|
|
40
|
+
[1.0, 1.0, 1.0],
|
|
41
|
+
[0.0, 1.0, 1.0],
|
|
42
|
+
[0.0, 1.0, 0.0],
|
|
43
|
+
]
|
|
44
|
+
indices = [
|
|
45
|
+
[1, 2, 3],
|
|
46
|
+
[7, 6, 5],
|
|
47
|
+
[4, 5, 1],
|
|
48
|
+
[5, 6, 2],
|
|
49
|
+
[2, 6, 7],
|
|
50
|
+
[0, 3, 7],
|
|
51
|
+
[0, 1, 3],
|
|
52
|
+
[4, 7, 5],
|
|
53
|
+
[0, 4, 1],
|
|
54
|
+
[1, 5, 2],
|
|
55
|
+
[3, 2, 7],
|
|
56
|
+
[4, 0, 7],
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
mass_0, com_0, I_0, volume_0 = compute_mesh_inertia(
|
|
60
|
+
density=1000, vertices=vertices, indices=indices, is_solid=True
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
self.assertAlmostEqual(mass_0, 1000.0, delta=1e-6)
|
|
64
|
+
self.assertAlmostEqual(volume_0, 1.0, delta=1e-6)
|
|
65
|
+
assert_np_equal(np.array(com_0), np.array([0.5, 0.5, 0.5]), tol=1e-6)
|
|
66
|
+
|
|
67
|
+
# Check against analytical inertia
|
|
68
|
+
mass_box, com_box, I_box = compute_box_inertia(1000.0, 1.0, 1.0, 1.0)
|
|
69
|
+
self.assertAlmostEqual(mass_box, mass_0, delta=1e-6)
|
|
70
|
+
assert_np_equal(np.array(com_box), np.zeros(3), tol=1e-6)
|
|
71
|
+
assert_np_equal(np.array(I_0), np.array(I_box), tol=1e-4)
|
|
72
|
+
|
|
73
|
+
# Compute hollow box inertia
|
|
74
|
+
mass_0_hollow, com_0_hollow, I_0_hollow, volume_0_hollow = compute_mesh_inertia(
|
|
75
|
+
density=1000,
|
|
76
|
+
vertices=vertices,
|
|
77
|
+
indices=indices,
|
|
78
|
+
is_solid=False,
|
|
79
|
+
thickness=0.1,
|
|
80
|
+
)
|
|
81
|
+
assert_np_equal(np.array(com_0_hollow), np.array([0.5, 0.5, 0.5]), tol=1e-6)
|
|
82
|
+
|
|
83
|
+
# Add vertex between [0.0, 0.0, 0.0] and [1.0, 0.0, 0.0]
|
|
84
|
+
vertices.append([0.5, 0.0, 0.0])
|
|
85
|
+
indices[5] = [0, 8, 7]
|
|
86
|
+
indices.append([8, 3, 7])
|
|
87
|
+
indices[6] = [0, 1, 8]
|
|
88
|
+
indices.append([8, 1, 3])
|
|
89
|
+
|
|
90
|
+
mass_1, com_1, I_1, volume_1 = compute_mesh_inertia(
|
|
91
|
+
density=1000, vertices=vertices, indices=indices, is_solid=True
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Inertia values should be the same as before
|
|
95
|
+
self.assertAlmostEqual(mass_1, mass_0, delta=1e-6)
|
|
96
|
+
self.assertAlmostEqual(volume_1, volume_0, delta=1e-6)
|
|
97
|
+
assert_np_equal(np.array(com_1), np.array([0.5, 0.5, 0.5]), tol=1e-6)
|
|
98
|
+
assert_np_equal(np.array(I_1), np.array(I_0), tol=1e-4)
|
|
99
|
+
|
|
100
|
+
# Compute hollow box inertia
|
|
101
|
+
mass_1_hollow, com_1_hollow, I_1_hollow, volume_1_hollow = compute_mesh_inertia(
|
|
102
|
+
density=1000,
|
|
103
|
+
vertices=vertices,
|
|
104
|
+
indices=indices,
|
|
105
|
+
is_solid=False,
|
|
106
|
+
thickness=0.1,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Inertia values should be the same as before
|
|
110
|
+
self.assertAlmostEqual(mass_1_hollow, mass_0_hollow, delta=2e-3)
|
|
111
|
+
self.assertAlmostEqual(volume_1_hollow, volume_0_hollow, delta=1e-6)
|
|
112
|
+
assert_np_equal(np.array(com_1_hollow), np.array([0.5, 0.5, 0.5]), tol=1e-6)
|
|
113
|
+
assert_np_equal(np.array(I_1_hollow), np.array(I_0_hollow), tol=1e-4)
|
|
114
|
+
|
|
115
|
+
def test_sphere_mesh_inertia(self):
|
|
116
|
+
vertices, indices = OpenGLRenderer._create_sphere_mesh(radius=2.5, num_latitudes=500, num_longitudes=500)
|
|
117
|
+
|
|
118
|
+
offset = np.array([1.0, 2.0, 3.0], dtype=np.float32)
|
|
119
|
+
vertices = vertices[:, :3] + offset
|
|
120
|
+
|
|
121
|
+
mass_mesh, com_mesh, I_mesh, vol_mesh = compute_mesh_inertia(
|
|
122
|
+
density=1000,
|
|
123
|
+
vertices=vertices,
|
|
124
|
+
indices=indices,
|
|
125
|
+
is_solid=True,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Check against analytical inertia
|
|
129
|
+
mass_sphere, _, I_sphere = compute_sphere_inertia(1000.0, 2.5)
|
|
130
|
+
self.assertAlmostEqual(mass_mesh, mass_sphere, delta=1e2)
|
|
131
|
+
assert_np_equal(np.array(com_mesh), np.array(offset), tol=2e-3)
|
|
132
|
+
assert_np_equal(np.array(I_mesh), np.array(I_sphere), tol=4e2)
|
|
133
|
+
# Check volume
|
|
134
|
+
self.assertAlmostEqual(vol_mesh, 4.0 / 3.0 * np.pi * 2.5**3, delta=3e-2)
|
|
135
|
+
|
|
136
|
+
def test_body_inertia(self):
|
|
137
|
+
vertices, indices = OpenGLRenderer._create_sphere_mesh(radius=2.5, num_latitudes=500, num_longitudes=500)
|
|
138
|
+
|
|
139
|
+
offset = np.array([1.0, 2.0, 3.0], dtype=np.float32)
|
|
140
|
+
vertices = vertices[:, :3] + offset
|
|
141
|
+
|
|
142
|
+
builder = ModelBuilder()
|
|
143
|
+
b = builder.add_body()
|
|
144
|
+
tf = wp.transform(wp.vec3(4.0, 5.0, 6.0), wp.quat_rpy(0.5, -0.8, 1.3))
|
|
145
|
+
builder.add_shape_mesh(
|
|
146
|
+
b,
|
|
147
|
+
pos=tf.p,
|
|
148
|
+
rot=tf.q,
|
|
149
|
+
mesh=wp.sim.Mesh(vertices=vertices, indices=indices),
|
|
150
|
+
density=1000.0,
|
|
151
|
+
)
|
|
152
|
+
transformed_com = wp.transform_point(tf, wp.vec3(*offset))
|
|
153
|
+
assert_np_equal(np.array(builder.body_com[0]), np.array(transformed_com), tol=2e-3)
|
|
154
|
+
mass_sphere, _, I_sphere = compute_sphere_inertia(1000.0, 2.5)
|
|
155
|
+
assert_np_equal(np.array(builder.body_inertia[0]), np.array(I_sphere), tol=4e2)
|
|
156
|
+
self.assertAlmostEqual(builder.body_mass[0], mass_sphere, delta=1e2)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
if __name__ == "__main__":
|
|
160
|
+
wp.clear_kernel_cache()
|
|
161
|
+
unittest.main(verbosity=2)
|