warp-lang 0.10.1__py3-none-win_amd64.whl → 0.11.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of warp-lang might be problematic. Click here for more details.
- warp/__init__.py +10 -4
- warp/__init__.pyi +1 -0
- warp/bin/warp-clang.dll +0 -0
- warp/bin/warp.dll +0 -0
- warp/build.py +5 -3
- warp/build_dll.py +29 -9
- warp/builtins.py +868 -507
- warp/codegen.py +1074 -638
- warp/config.py +3 -3
- warp/constants.py +6 -0
- warp/context.py +715 -222
- warp/fabric.py +326 -0
- warp/fem/__init__.py +27 -0
- warp/fem/cache.py +389 -0
- warp/fem/dirichlet.py +181 -0
- warp/fem/domain.py +263 -0
- warp/fem/field/__init__.py +101 -0
- warp/fem/field/field.py +149 -0
- warp/fem/field/nodal_field.py +299 -0
- warp/fem/field/restriction.py +21 -0
- warp/fem/field/test.py +181 -0
- warp/fem/field/trial.py +183 -0
- warp/fem/geometry/__init__.py +19 -0
- warp/fem/geometry/closest_point.py +70 -0
- warp/fem/geometry/deformed_geometry.py +271 -0
- warp/fem/geometry/element.py +744 -0
- warp/fem/geometry/geometry.py +186 -0
- warp/fem/geometry/grid_2d.py +373 -0
- warp/fem/geometry/grid_3d.py +435 -0
- warp/fem/geometry/hexmesh.py +953 -0
- warp/fem/geometry/partition.py +376 -0
- warp/fem/geometry/quadmesh_2d.py +532 -0
- warp/fem/geometry/tetmesh.py +840 -0
- warp/fem/geometry/trimesh_2d.py +577 -0
- warp/fem/integrate.py +1616 -0
- warp/fem/operator.py +191 -0
- warp/fem/polynomial.py +213 -0
- warp/fem/quadrature/__init__.py +2 -0
- warp/fem/quadrature/pic_quadrature.py +245 -0
- warp/fem/quadrature/quadrature.py +294 -0
- warp/fem/space/__init__.py +292 -0
- warp/fem/space/basis_space.py +489 -0
- warp/fem/space/collocated_function_space.py +105 -0
- warp/fem/space/dof_mapper.py +236 -0
- warp/fem/space/function_space.py +145 -0
- warp/fem/space/grid_2d_function_space.py +267 -0
- warp/fem/space/grid_3d_function_space.py +306 -0
- warp/fem/space/hexmesh_function_space.py +352 -0
- warp/fem/space/partition.py +350 -0
- warp/fem/space/quadmesh_2d_function_space.py +369 -0
- warp/fem/space/restriction.py +160 -0
- warp/fem/space/shape/__init__.py +15 -0
- warp/fem/space/shape/cube_shape_function.py +738 -0
- warp/fem/space/shape/shape_function.py +103 -0
- warp/fem/space/shape/square_shape_function.py +611 -0
- warp/fem/space/shape/tet_shape_function.py +567 -0
- warp/fem/space/shape/triangle_shape_function.py +429 -0
- warp/fem/space/tetmesh_function_space.py +292 -0
- warp/fem/space/topology.py +295 -0
- warp/fem/space/trimesh_2d_function_space.py +221 -0
- warp/fem/types.py +77 -0
- warp/fem/utils.py +495 -0
- warp/native/array.h +147 -44
- warp/native/builtin.h +122 -149
- warp/native/bvh.cpp +73 -325
- warp/native/bvh.cu +406 -23
- warp/native/bvh.h +34 -43
- warp/native/clang/clang.cpp +13 -8
- warp/native/crt.h +2 -0
- warp/native/cuda_crt.h +5 -0
- warp/native/cuda_util.cpp +15 -3
- warp/native/cuda_util.h +3 -1
- warp/native/cutlass/tools/library/scripts/conv2d_operation.py +463 -0
- warp/native/cutlass/tools/library/scripts/conv3d_operation.py +321 -0
- warp/native/cutlass/tools/library/scripts/gemm_operation.py +988 -0
- warp/native/cutlass/tools/library/scripts/generator.py +4625 -0
- warp/native/cutlass/tools/library/scripts/library.py +799 -0
- warp/native/cutlass/tools/library/scripts/manifest.py +402 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/docs/source/conf.py +96 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/profile/conv/conv2d_f16_sm80.py +106 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/profile/gemm/gemm_f32_sm80.py +91 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/setup.py +80 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/__init__.py +48 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/arguments.py +118 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/c_types.py +241 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/compiler.py +432 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/conv2d_operation.py +631 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/epilogue.py +1026 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/frontend.py +104 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/gemm_operation.py +1276 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/library.py +744 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/memory_manager.py +74 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/operation.py +110 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/parser.py +619 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/reduction_operation.py +398 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/tensor_ref.py +70 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/__init__.py +4 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/conv2d_testbed.py +646 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/gemm_grouped_testbed.py +235 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/gemm_testbed.py +557 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/profiler.py +70 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/type_hint.py +39 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/utils/__init__.py +1 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/utils/device.py +76 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/utils/reference_model.py +255 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/__init__.py +0 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.py +201 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +177 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.py +98 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.py +95 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_few_channels_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.py +163 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_fixed_channels_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.py +187 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.py +309 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +54 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.py +96 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.py +107 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_strided_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +253 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.py +97 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +242 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.py +96 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.py +107 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/run_all_tests.py +10 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/frontend/test_frontend.py +146 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/__init__.py +0 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_bf16_sm80.py +96 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_f16_sm80.py +447 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_f32_sm80.py +146 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_f64_sm80.py +102 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_grouped_sm80.py +203 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_s8_sm80.py +229 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/run_all_tests.py +9 -0
- warp/native/cutlass/tools/library/scripts/pycutlass/test/unit/test_sm80.py +453 -0
- warp/native/cutlass/tools/library/scripts/rank_2k_operation.py +398 -0
- warp/native/cutlass/tools/library/scripts/rank_k_operation.py +387 -0
- warp/native/cutlass/tools/library/scripts/rt.py +796 -0
- warp/native/cutlass/tools/library/scripts/symm_operation.py +400 -0
- warp/native/cutlass/tools/library/scripts/trmm_operation.py +407 -0
- warp/native/cutlass_gemm.cu +5 -3
- warp/native/exports.h +1240 -952
- warp/native/fabric.h +228 -0
- warp/native/hashgrid.cpp +4 -4
- warp/native/hashgrid.h +22 -2
- warp/native/intersect.h +22 -7
- warp/native/intersect_adj.h +8 -8
- warp/native/intersect_tri.h +1 -1
- warp/native/marching.cu +157 -161
- warp/native/mat.h +80 -19
- warp/native/matnn.h +2 -2
- warp/native/mesh.cpp +33 -108
- warp/native/mesh.cu +114 -23
- warp/native/mesh.h +446 -46
- warp/native/noise.h +272 -329
- warp/native/quat.h +51 -8
- warp/native/rand.h +45 -35
- warp/native/range.h +6 -2
- warp/native/reduce.cpp +1 -1
- warp/native/reduce.cu +10 -12
- warp/native/runlength_encode.cu +6 -10
- warp/native/scan.cu +8 -11
- warp/native/sparse.cpp +4 -4
- warp/native/sparse.cu +164 -154
- warp/native/spatial.h +2 -2
- warp/native/temp_buffer.h +14 -30
- warp/native/vec.h +107 -23
- warp/native/volume.h +120 -0
- warp/native/warp.cpp +560 -30
- warp/native/warp.cu +431 -44
- warp/native/warp.h +13 -4
- warp/optim/__init__.py +1 -0
- warp/optim/linear.py +922 -0
- warp/optim/sgd.py +92 -0
- warp/render/render_opengl.py +335 -119
- warp/render/render_usd.py +11 -11
- warp/sim/__init__.py +2 -2
- warp/sim/articulation.py +385 -185
- warp/sim/collide.py +8 -0
- warp/sim/import_mjcf.py +297 -106
- warp/sim/import_urdf.py +389 -210
- warp/sim/import_usd.py +198 -97
- warp/sim/inertia.py +17 -18
- warp/sim/integrator_euler.py +14 -8
- warp/sim/integrator_xpbd.py +158 -16
- warp/sim/model.py +795 -291
- warp/sim/render.py +3 -3
- warp/sim/utils.py +3 -0
- warp/sparse.py +640 -150
- warp/stubs.py +606 -267
- warp/tape.py +61 -10
- warp/tests/__main__.py +3 -6
- warp/tests/assets/curlnoise_golden.npy +0 -0
- warp/tests/assets/pnoise_golden.npy +0 -0
- warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
- warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
- warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
- warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
- warp/tests/aux_test_unresolved_func.py +14 -0
- warp/tests/aux_test_unresolved_symbol.py +14 -0
- warp/tests/disabled_kinematics.py +239 -0
- warp/tests/run_coverage_serial.py +31 -0
- warp/tests/test_adam.py +103 -106
- warp/tests/test_arithmetic.py +128 -74
- warp/tests/test_array.py +212 -97
- warp/tests/test_array_reduce.py +57 -23
- warp/tests/test_atomic.py +64 -28
- warp/tests/test_bool.py +99 -0
- warp/tests/test_builtins_resolution.py +1292 -0
- warp/tests/test_bvh.py +42 -18
- warp/tests/test_closest_point_edge_edge.py +54 -57
- warp/tests/test_codegen.py +208 -130
- warp/tests/test_compile_consts.py +28 -20
- warp/tests/test_conditional.py +108 -24
- warp/tests/test_copy.py +10 -12
- warp/tests/test_ctypes.py +112 -88
- warp/tests/test_dense.py +21 -14
- warp/tests/test_devices.py +98 -0
- warp/tests/test_dlpack.py +75 -75
- warp/tests/test_examples.py +277 -0
- warp/tests/test_fabricarray.py +955 -0
- warp/tests/test_fast_math.py +15 -11
- warp/tests/test_fem.py +1271 -0
- warp/tests/test_fp16.py +53 -19
- warp/tests/test_func.py +187 -86
- warp/tests/test_generics.py +194 -49
- warp/tests/test_grad.py +178 -109
- warp/tests/test_grad_customs.py +176 -0
- warp/tests/test_hash_grid.py +52 -37
- warp/tests/test_import.py +10 -23
- warp/tests/test_indexedarray.py +32 -31
- warp/tests/test_intersect.py +18 -9
- warp/tests/test_large.py +141 -0
- warp/tests/test_launch.py +14 -41
- warp/tests/test_lerp.py +64 -65
- warp/tests/test_linear_solvers.py +154 -0
- warp/tests/test_lvalue.py +493 -0
- warp/tests/test_marching_cubes.py +12 -13
- warp/tests/test_mat.py +517 -2898
- warp/tests/test_mat_lite.py +115 -0
- warp/tests/test_mat_scalar_ops.py +2889 -0
- warp/tests/test_math.py +103 -9
- warp/tests/test_matmul.py +305 -69
- warp/tests/test_matmul_lite.py +410 -0
- warp/tests/test_mesh.py +71 -14
- warp/tests/test_mesh_query_aabb.py +41 -25
- warp/tests/test_mesh_query_point.py +140 -22
- warp/tests/test_mesh_query_ray.py +39 -22
- warp/tests/test_mlp.py +30 -22
- warp/tests/test_model.py +92 -89
- warp/tests/test_modules_lite.py +39 -0
- warp/tests/test_multigpu.py +88 -114
- warp/tests/test_noise.py +12 -11
- warp/tests/test_operators.py +16 -20
- warp/tests/test_options.py +11 -11
- warp/tests/test_pinned.py +17 -18
- warp/tests/test_print.py +32 -11
- warp/tests/test_quat.py +275 -129
- warp/tests/test_rand.py +18 -16
- warp/tests/test_reload.py +38 -34
- warp/tests/test_rounding.py +50 -43
- warp/tests/test_runlength_encode.py +168 -20
- warp/tests/test_smoothstep.py +9 -11
- warp/tests/test_snippet.py +143 -0
- warp/tests/test_sparse.py +261 -63
- warp/tests/test_spatial.py +276 -243
- warp/tests/test_streams.py +110 -85
- warp/tests/test_struct.py +268 -63
- warp/tests/test_tape.py +39 -21
- warp/tests/test_torch.py +118 -89
- warp/tests/test_transient_module.py +12 -13
- warp/tests/test_types.py +614 -0
- warp/tests/test_utils.py +494 -0
- warp/tests/test_vec.py +354 -2050
- warp/tests/test_vec_lite.py +73 -0
- warp/tests/test_vec_scalar_ops.py +2099 -0
- warp/tests/test_volume.py +457 -293
- warp/tests/test_volume_write.py +124 -134
- warp/tests/unittest_serial.py +35 -0
- warp/tests/unittest_suites.py +341 -0
- warp/tests/unittest_utils.py +568 -0
- warp/tests/unused_test_misc.py +71 -0
- warp/tests/{test_debug.py → walkthough_debug.py} +3 -17
- warp/thirdparty/appdirs.py +36 -45
- warp/thirdparty/unittest_parallel.py +549 -0
- warp/torch.py +9 -6
- warp/types.py +1089 -366
- warp/utils.py +93 -387
- warp_lang-0.11.0.dist-info/METADATA +238 -0
- warp_lang-0.11.0.dist-info/RECORD +332 -0
- {warp_lang-0.10.1.dist-info → warp_lang-0.11.0.dist-info}/WHEEL +1 -1
- warp/tests/test_all.py +0 -219
- warp/tests/test_array_scan.py +0 -60
- warp/tests/test_base.py +0 -208
- warp/tests/test_unresolved_func.py +0 -7
- warp/tests/test_unresolved_symbol.py +0 -7
- warp_lang-0.10.1.dist-info/METADATA +0 -21
- warp_lang-0.10.1.dist-info/RECORD +0 -188
- /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
- /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
- /warp/tests/{test_square.py → aux_test_square.py} +0 -0
- {warp_lang-0.10.1.dist-info → warp_lang-0.11.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-0.10.1.dist-info → warp_lang-0.11.0.dist-info}/top_level.txt +0 -0
warp/sim/model.py
CHANGED
|
@@ -8,21 +8,23 @@
|
|
|
8
8
|
"""A module for building simulation models and state.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
from
|
|
14
|
-
from .inertia import compute_capsule_inertia
|
|
15
|
-
from .inertia import compute_box_inertia
|
|
16
|
-
from .inertia import compute_sphere_inertia
|
|
17
|
-
from .inertia import compute_mesh_inertia
|
|
11
|
+
import copy
|
|
12
|
+
import math
|
|
13
|
+
from typing import List, Optional, Tuple
|
|
18
14
|
|
|
19
|
-
import warp as wp
|
|
20
15
|
import numpy as np
|
|
21
16
|
|
|
22
|
-
import
|
|
23
|
-
import copy
|
|
17
|
+
import warp as wp
|
|
24
18
|
|
|
25
|
-
from
|
|
19
|
+
from .inertia import (
|
|
20
|
+
compute_box_inertia,
|
|
21
|
+
compute_capsule_inertia,
|
|
22
|
+
compute_cone_inertia,
|
|
23
|
+
compute_cylinder_inertia,
|
|
24
|
+
compute_mesh_inertia,
|
|
25
|
+
compute_sphere_inertia,
|
|
26
|
+
transform_inertia,
|
|
27
|
+
)
|
|
26
28
|
|
|
27
29
|
Vec3 = List[float]
|
|
28
30
|
Vec4 = List[float]
|
|
@@ -92,11 +94,27 @@ class ModelShapeGeometry:
|
|
|
92
94
|
|
|
93
95
|
# Axis (linear or angular) of a joint that can have bounds and be driven towards a target
|
|
94
96
|
class JointAxis:
|
|
97
|
+
"""
|
|
98
|
+
Describes a joint axis that can have limits and be driven towards a target.
|
|
99
|
+
|
|
100
|
+
Attributes:
|
|
101
|
+
|
|
102
|
+
axis (3D vector or JointAxis): The 3D axis that this JointAxis object describes, or alternatively another JointAxis object to copy from
|
|
103
|
+
limit_lower (float): The lower limit of the joint axis
|
|
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 :class:`SemiImplicitIntegrator`
|
|
106
|
+
limit_kd (float): The damping stiffness of the joint axis limits, only respected by :class:`SemiImplicitIntegrator`
|
|
107
|
+
target (float): The target position or velocity (depending on the mode, see `Joint modes`_) of the joint axis
|
|
108
|
+
target_ke (float): The proportional gain of the joint axis target drive PD controller
|
|
109
|
+
target_kd (float): The derivative gain of the joint axis target drive PD controller
|
|
110
|
+
mode (int): The mode of the joint axis, see `Joint modes`_
|
|
111
|
+
"""
|
|
112
|
+
|
|
95
113
|
def __init__(
|
|
96
114
|
self,
|
|
97
115
|
axis,
|
|
98
|
-
limit_lower=-
|
|
99
|
-
limit_upper=
|
|
116
|
+
limit_lower=-math.inf,
|
|
117
|
+
limit_upper=math.inf,
|
|
100
118
|
limit_ke=100.0,
|
|
101
119
|
limit_kd=10.0,
|
|
102
120
|
target=None,
|
|
@@ -104,30 +122,92 @@ class JointAxis:
|
|
|
104
122
|
target_kd=0.0,
|
|
105
123
|
mode=JOINT_MODE_TARGET_POSITION,
|
|
106
124
|
):
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
self.target = target
|
|
114
|
-
|
|
115
|
-
self.
|
|
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
|
|
116
135
|
else:
|
|
117
|
-
self.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class SDF:
|
|
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()):
|
|
163
|
+
self.volume = volume
|
|
164
|
+
self.I = I
|
|
165
|
+
self.mass = mass
|
|
166
|
+
self.com = com
|
|
167
|
+
|
|
168
|
+
# Need to specify these for now
|
|
169
|
+
self.has_inertia = True
|
|
170
|
+
self.is_solid = True
|
|
171
|
+
|
|
172
|
+
def finalize(self, device=None):
|
|
173
|
+
return self.volume.id
|
|
174
|
+
|
|
175
|
+
def __hash__(self):
|
|
176
|
+
return hash((self.volume.id))
|
|
121
177
|
|
|
122
178
|
|
|
123
179
|
class Mesh:
|
|
124
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")
|
|
125
205
|
|
|
126
206
|
Attributes:
|
|
127
207
|
|
|
128
|
-
vertices (List[Vec3]): Mesh vertices
|
|
129
|
-
indices (List[int]): Mesh indices
|
|
130
|
-
I (Mat33):
|
|
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)
|
|
131
211
|
mass (float): The total mass of the body assuming density of 1.0
|
|
132
212
|
com (Vec3): The center of mass of the body
|
|
133
213
|
"""
|
|
@@ -146,20 +226,28 @@ class Mesh:
|
|
|
146
226
|
is_solid: If True, the mesh is assumed to be a solid during inertia computation, otherwise it is assumed to be a hollow surface
|
|
147
227
|
"""
|
|
148
228
|
|
|
149
|
-
self.vertices = vertices
|
|
150
|
-
self.indices = indices
|
|
229
|
+
self.vertices = np.array(vertices).reshape(-1, 3)
|
|
230
|
+
self.indices = np.array(indices, dtype=np.int32).flatten()
|
|
151
231
|
self.is_solid = is_solid
|
|
152
232
|
self.has_inertia = compute_inertia
|
|
153
233
|
|
|
154
234
|
if compute_inertia:
|
|
155
235
|
self.mass, self.com, self.I, _ = compute_mesh_inertia(1.0, vertices, indices, is_solid=is_solid)
|
|
156
236
|
else:
|
|
157
|
-
self.I = np.eye(3
|
|
237
|
+
self.I = wp.mat33(np.eye(3))
|
|
158
238
|
self.mass = 1.0
|
|
159
|
-
self.com =
|
|
239
|
+
self.com = wp.vec3()
|
|
160
240
|
|
|
161
|
-
# construct simulation ready buffers from points
|
|
162
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
|
+
"""
|
|
163
251
|
with wp.ScopedDevice(device):
|
|
164
252
|
pos = wp.array(self.vertices, dtype=wp.vec3)
|
|
165
253
|
vel = wp.zeros_like(pos)
|
|
@@ -169,6 +257,9 @@ class Mesh:
|
|
|
169
257
|
return self.mesh.id
|
|
170
258
|
|
|
171
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
|
+
"""
|
|
172
263
|
return hash((tuple(np.array(self.vertices).flatten()), tuple(np.array(self.indices).flatten()), self.is_solid))
|
|
173
264
|
|
|
174
265
|
|
|
@@ -183,11 +274,16 @@ class State:
|
|
|
183
274
|
|
|
184
275
|
Attributes:
|
|
185
276
|
|
|
186
|
-
|
|
187
|
-
|
|
277
|
+
particle_count (int): Number of particles
|
|
278
|
+
body_count (int): Number of rigid bodies
|
|
279
|
+
|
|
280
|
+
particle_q (array): Tensor of particle positions
|
|
281
|
+
particle_qd (array): Tensor of particle velocities
|
|
282
|
+
particle_f (array): Tensor of particle forces
|
|
188
283
|
|
|
189
|
-
body_q (
|
|
190
|
-
body_qd (
|
|
284
|
+
body_q (array): Tensor of body coordinates
|
|
285
|
+
body_qd (array): Tensor of body velocities
|
|
286
|
+
body_f (array): Tensor of body forces
|
|
191
287
|
|
|
192
288
|
"""
|
|
193
289
|
|
|
@@ -195,6 +291,14 @@ class State:
|
|
|
195
291
|
self.particle_count = 0
|
|
196
292
|
self.body_count = 0
|
|
197
293
|
|
|
294
|
+
self.particle_q = None
|
|
295
|
+
self.particle_qd = None
|
|
296
|
+
self.particle_f = None
|
|
297
|
+
|
|
298
|
+
self.body_q = None
|
|
299
|
+
self.body_qd = None
|
|
300
|
+
self.body_f = None
|
|
301
|
+
|
|
198
302
|
def clear_forces(self):
|
|
199
303
|
if self.particle_count:
|
|
200
304
|
self.particle_f.zero_()
|
|
@@ -203,25 +307,25 @@ class State:
|
|
|
203
307
|
self.body_f.zero_()
|
|
204
308
|
|
|
205
309
|
def flatten(self):
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
310
|
+
wp.utils.warn(
|
|
311
|
+
"Model.flatten() will be removed in a future Warp version.",
|
|
312
|
+
DeprecationWarning,
|
|
313
|
+
stacklevel=2,
|
|
314
|
+
)
|
|
211
315
|
|
|
212
|
-
|
|
316
|
+
arrays = []
|
|
213
317
|
|
|
214
318
|
# build a list of all tensor attributes
|
|
215
319
|
for attr, value in self.__dict__.items():
|
|
216
|
-
if wp.
|
|
217
|
-
|
|
320
|
+
if isinstance(value, wp.array):
|
|
321
|
+
arrays.append(value)
|
|
218
322
|
|
|
219
|
-
return
|
|
323
|
+
return arrays
|
|
220
324
|
|
|
221
325
|
|
|
222
326
|
def compute_shape_mass(type, scale, src, density, is_solid, thickness):
|
|
223
327
|
if density == 0.0 or type == GEO_PLANE: # zero density means fixed
|
|
224
|
-
return 0.0,
|
|
328
|
+
return 0.0, wp.vec3(), wp.mat33()
|
|
225
329
|
|
|
226
330
|
if type == GEO_SPHERE:
|
|
227
331
|
solid = compute_sphere_inertia(density, scale[0])
|
|
@@ -231,7 +335,7 @@ def compute_shape_mass(type, scale, src, density, is_solid, thickness):
|
|
|
231
335
|
hollow = compute_sphere_inertia(density, scale[0] - thickness)
|
|
232
336
|
return solid[0] - hollow[0], solid[1], solid[2] - hollow[2]
|
|
233
337
|
elif type == GEO_BOX:
|
|
234
|
-
w, h, d =
|
|
338
|
+
w, h, d = scale * 2.0
|
|
235
339
|
solid = compute_box_inertia(density, w, h, d)
|
|
236
340
|
if is_solid:
|
|
237
341
|
return solid
|
|
@@ -262,17 +366,16 @@ def compute_shape_mass(type, scale, src, density, is_solid, thickness):
|
|
|
262
366
|
else:
|
|
263
367
|
hollow = compute_cone_inertia(density, r - thickness, h - 2.0 * thickness)
|
|
264
368
|
return solid[0] - hollow[0], solid[1], solid[2] - hollow[2]
|
|
265
|
-
elif type == GEO_MESH:
|
|
369
|
+
elif type == GEO_MESH or type == GEO_SDF:
|
|
266
370
|
if src.has_inertia and src.mass > 0.0 and src.is_solid == is_solid:
|
|
267
371
|
m, c, I = src.mass, src.com, src.I
|
|
268
372
|
|
|
269
|
-
|
|
270
|
-
sx, sy, sz = s
|
|
373
|
+
sx, sy, sz = scale
|
|
271
374
|
|
|
272
375
|
mass_ratio = sx * sy * sz * density
|
|
273
376
|
m_new = m * mass_ratio
|
|
274
377
|
|
|
275
|
-
c_new = c
|
|
378
|
+
c_new = wp.cw_mul(c, scale)
|
|
276
379
|
|
|
277
380
|
Ixx = I[0, 0] * (sy**2 + sz**2) / 2 * mass_ratio
|
|
278
381
|
Iyy = I[1, 1] * (sx**2 + sz**2) / 2 * mass_ratio
|
|
@@ -281,12 +384,12 @@ def compute_shape_mass(type, scale, src, density, is_solid, thickness):
|
|
|
281
384
|
Ixz = I[0, 2] * sx * sz * mass_ratio
|
|
282
385
|
Iyz = I[1, 2] * sy * sz * mass_ratio
|
|
283
386
|
|
|
284
|
-
I_new =
|
|
387
|
+
I_new = wp.mat33([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]])
|
|
285
388
|
|
|
286
389
|
return m_new, c_new, I_new
|
|
287
|
-
|
|
390
|
+
elif type == GEO_MESH:
|
|
288
391
|
# fall back to computing inertia from mesh geometry
|
|
289
|
-
vertices = np.array(src.vertices) * np.array(scale
|
|
392
|
+
vertices = np.array(src.vertices) * np.array(scale)
|
|
290
393
|
m, c, I, vol = compute_mesh_inertia(density, vertices, src.indices, is_solid, thickness)
|
|
291
394
|
return m, c, I
|
|
292
395
|
raise ValueError("Unsupported shape type: {}".format(type))
|
|
@@ -302,23 +405,24 @@ class Model:
|
|
|
302
405
|
requires_grad (float): Indicates whether the model was finalized with gradient computation enabled
|
|
303
406
|
num_envs (int): Number of articulation environments that were added to the ModelBuilder via `add_builder`
|
|
304
407
|
|
|
305
|
-
particle_q (
|
|
306
|
-
particle_qd (
|
|
307
|
-
particle_mass (
|
|
308
|
-
particle_inv_mass (
|
|
309
|
-
particle_radius (
|
|
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
|
|
310
413
|
particle_max_radius (float): Maximum particle radius (useful for HashGrid construction)
|
|
311
|
-
particle_ke (
|
|
312
|
-
particle_kd (
|
|
313
|
-
particle_kf (
|
|
314
|
-
particle_mu (
|
|
315
|
-
particle_cohesion (
|
|
316
|
-
particle_adhesion (
|
|
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
|
|
317
420
|
particle_grid (HashGrid): HashGrid instance used for accelerated simulation of particle interactions
|
|
318
|
-
particle_flags (
|
|
421
|
+
particle_flags (array): Particle enabled state, shape [particle_count], bool
|
|
422
|
+
particle_max_velocity (float): Maximum particle velocity (to prevent instability)
|
|
319
423
|
|
|
320
|
-
shape_transform (
|
|
321
|
-
shape_body (
|
|
424
|
+
shape_transform (array): Rigid shape transforms, shape [shape_count, 7], float
|
|
425
|
+
shape_body (array): Rigid shape body index, shape [shape_count], int
|
|
322
426
|
body_shapes (dict): Mapping from body index to list of attached shape indices
|
|
323
427
|
shape_materials (ModelShapeMaterials): Rigid shape contact materials, shape [shape_count], float
|
|
324
428
|
shape_shape_geo (ModelShapeGeometry): Shape geometry properties (geo type, scale, thickness, etc.), shape [shape_count, 3], float
|
|
@@ -327,73 +431,72 @@ class Model:
|
|
|
327
431
|
shape_collision_group (list): Collision group of each shape, shape [shape_count], int
|
|
328
432
|
shape_collision_group_map (dict): Mapping from collision group to list of shape indices
|
|
329
433
|
shape_collision_filter_pairs (set): Pairs of shape indices that should not collide
|
|
330
|
-
shape_collision_radius (
|
|
434
|
+
shape_collision_radius (array): Collision radius of each shape used for bounding sphere broadphase collision checking, shape [shape_count], float
|
|
331
435
|
shape_ground_collision (list): Indicates whether each shape should collide with the ground, shape [shape_count], bool
|
|
332
|
-
shape_contact_pairs (
|
|
333
|
-
shape_ground_contact_pairs (
|
|
334
|
-
|
|
335
|
-
spring_indices (
|
|
336
|
-
spring_rest_length (
|
|
337
|
-
spring_stiffness (
|
|
338
|
-
spring_damping (
|
|
339
|
-
spring_control (
|
|
340
|
-
|
|
341
|
-
tri_indices (
|
|
342
|
-
tri_poses (
|
|
343
|
-
tri_activations (
|
|
344
|
-
tri_materials (
|
|
345
|
-
|
|
346
|
-
edge_indices (
|
|
347
|
-
edge_rest_angle (
|
|
348
|
-
edge_bending_properties (
|
|
349
|
-
|
|
350
|
-
tet_indices (
|
|
351
|
-
tet_poses (
|
|
352
|
-
tet_activations (
|
|
353
|
-
tet_materials (
|
|
354
|
-
|
|
355
|
-
body_q (
|
|
356
|
-
body_qd (
|
|
357
|
-
body_com (
|
|
358
|
-
body_inertia (
|
|
359
|
-
body_inv_inertia (
|
|
360
|
-
body_mass (
|
|
361
|
-
body_inv_mass (
|
|
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
|
|
362
466
|
body_name (list): Rigid body names, shape [body_count], str
|
|
363
467
|
|
|
364
|
-
joint_q (
|
|
365
|
-
joint_qd (
|
|
366
|
-
joint_act (
|
|
367
|
-
joint_type (
|
|
368
|
-
joint_parent (
|
|
369
|
-
joint_child (
|
|
370
|
-
joint_X_p (
|
|
371
|
-
joint_X_c (
|
|
372
|
-
joint_axis (
|
|
373
|
-
joint_armature (
|
|
374
|
-
joint_target (
|
|
375
|
-
joint_target_ke (
|
|
376
|
-
joint_target_kd (
|
|
377
|
-
joint_axis_start (
|
|
378
|
-
joint_axis_dim (
|
|
379
|
-
joint_axis_mode (
|
|
380
|
-
joint_linear_compliance (
|
|
381
|
-
joint_angular_compliance (
|
|
382
|
-
joint_enabled (
|
|
383
|
-
joint_limit_lower (
|
|
384
|
-
joint_limit_upper (
|
|
385
|
-
joint_limit_ke (
|
|
386
|
-
joint_limit_kd (
|
|
387
|
-
joint_twist_lower (
|
|
388
|
-
joint_twist_upper (
|
|
389
|
-
joint_q_start (
|
|
390
|
-
joint_qd_start (
|
|
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
|
|
391
496
|
joint_name (list): Joint names, shape [joint_count], str
|
|
392
497
|
joint_attach_ke (float): Joint attachment force stiffness (used by SemiImplicitIntegrator)
|
|
393
498
|
joint_attach_kd (float): Joint attachment force damping (used by SemiImplicitIntegrator)
|
|
394
499
|
|
|
395
|
-
articulation_start (wp.array): Articulation start index, shape [articulation_count], int
|
|
396
|
-
|
|
397
500
|
soft_contact_margin (float): Contact margin for generation of soft contacts
|
|
398
501
|
soft_contact_ke (float): Stiffness of soft contacts (used by SemiImplicitIntegrator)
|
|
399
502
|
soft_contact_kd (float): Damping of soft contacts (used by SemiImplicitIntegrator)
|
|
@@ -406,7 +509,7 @@ class Model:
|
|
|
406
509
|
rigid_contact_rolling_friction (float): Rolling friction coefficient for rigid body contacts (used by XPBDIntegrator)
|
|
407
510
|
|
|
408
511
|
ground (bool): Whether the ground plane and ground contacts are enabled
|
|
409
|
-
ground_plane (
|
|
512
|
+
ground_plane (array): Ground plane 3D normal and offset, shape [4], float
|
|
410
513
|
up_vector (np.ndarray): Up vector of the world, shape [3], float
|
|
411
514
|
up_axis (int): Up axis, 0 for x, 1 for y, 2 for z
|
|
412
515
|
gravity (np.ndarray): Gravity vector, shape [3], float
|
|
@@ -451,6 +554,7 @@ class Model:
|
|
|
451
554
|
self.particle_adhesion = 0.0
|
|
452
555
|
self.particle_grid = None
|
|
453
556
|
self.particle_flags = None
|
|
557
|
+
self.particle_max_velocity = 1e5
|
|
454
558
|
|
|
455
559
|
self.shape_transform = None
|
|
456
560
|
self.shape_body = None
|
|
@@ -522,6 +626,8 @@ class Model:
|
|
|
522
626
|
self.joint_twist_lower = None
|
|
523
627
|
self.joint_twist_upper = None
|
|
524
628
|
self.joint_q_start = None
|
|
629
|
+
self.joint_qd_start = None
|
|
630
|
+
self.articulation_start = None
|
|
525
631
|
self.joint_name = None
|
|
526
632
|
|
|
527
633
|
# todo: per-joint values?
|
|
@@ -562,7 +668,7 @@ class Model:
|
|
|
562
668
|
|
|
563
669
|
self.device = wp.get_device(device)
|
|
564
670
|
|
|
565
|
-
def state(self, requires_grad=
|
|
671
|
+
def state(self, requires_grad=None) -> State:
|
|
566
672
|
"""Returns a state object for the model
|
|
567
673
|
|
|
568
674
|
The returned state will be initialized with the initial configuration given in
|
|
@@ -570,6 +676,8 @@ class Model:
|
|
|
570
676
|
"""
|
|
571
677
|
|
|
572
678
|
s = State()
|
|
679
|
+
if requires_grad is None:
|
|
680
|
+
requires_grad = self.requires_grad
|
|
573
681
|
|
|
574
682
|
s.particle_count = self.particle_count
|
|
575
683
|
s.body_count = self.body_count
|
|
@@ -577,15 +685,6 @@ class Model:
|
|
|
577
685
|
# --------------------------------
|
|
578
686
|
# dynamic state (input, output)
|
|
579
687
|
|
|
580
|
-
s.particle_q = None
|
|
581
|
-
s.particle_qd = None
|
|
582
|
-
s.particle_f = None
|
|
583
|
-
|
|
584
|
-
s.body_q = None
|
|
585
|
-
s.body_qd = None
|
|
586
|
-
s.body_f = None
|
|
587
|
-
s.body_deltas = None
|
|
588
|
-
|
|
589
688
|
# particles
|
|
590
689
|
if self.particle_count:
|
|
591
690
|
s.particle_q = wp.clone(self.particle_q)
|
|
@@ -622,8 +721,8 @@ class Model:
|
|
|
622
721
|
|
|
623
722
|
def find_shape_contact_pairs(self):
|
|
624
723
|
# find potential contact pairs based on collision groups and collision mask (pairwise filtering)
|
|
625
|
-
import itertools
|
|
626
724
|
import copy
|
|
725
|
+
import itertools
|
|
627
726
|
|
|
628
727
|
filters = copy.copy(self.shape_collision_filter_pairs)
|
|
629
728
|
for a, b in self.shape_collision_filter_pairs:
|
|
@@ -775,9 +874,7 @@ class Model:
|
|
|
775
874
|
return tensors
|
|
776
875
|
|
|
777
876
|
def collide(self, state: State):
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
warnings.warn(
|
|
877
|
+
wp.utils.warn(
|
|
781
878
|
"Model.collide() is not needed anymore and will be removed in a future Warp version.",
|
|
782
879
|
DeprecationWarning,
|
|
783
880
|
stacklevel=2,
|
|
@@ -790,9 +887,7 @@ class Model:
|
|
|
790
887
|
|
|
791
888
|
@property
|
|
792
889
|
def soft_contact_distance(self):
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
warnings.warn(
|
|
890
|
+
wp.utils.warn(
|
|
796
891
|
"Model.soft_contact_distance is deprecated and will be removed in a future Warp version. "
|
|
797
892
|
"Particles now have individual radii, returning `Model.particle_max_radius`.",
|
|
798
893
|
DeprecationWarning,
|
|
@@ -802,9 +897,7 @@ class Model:
|
|
|
802
897
|
|
|
803
898
|
@soft_contact_distance.setter
|
|
804
899
|
def soft_contact_distance(self, value):
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
warnings.warn(
|
|
900
|
+
wp.utils.warn(
|
|
808
901
|
"Model.soft_contact_distance is deprecated and will be removed in a future Warp version. "
|
|
809
902
|
"Particles now have individual radii, see `Model.particle_radius`.",
|
|
810
903
|
DeprecationWarning,
|
|
@@ -813,18 +906,16 @@ class Model:
|
|
|
813
906
|
|
|
814
907
|
@property
|
|
815
908
|
def particle_radius(self):
|
|
816
|
-
|
|
909
|
+
# Array of per-particle radii
|
|
817
910
|
return self._particle_radius
|
|
818
911
|
|
|
819
912
|
@particle_radius.setter
|
|
820
913
|
def particle_radius(self, value):
|
|
821
914
|
if isinstance(value, float):
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
warnings.warn(
|
|
915
|
+
wp.utils.warn(
|
|
825
916
|
"Model.particle_radius is an array of per-particle radii, assigning with a scalar value "
|
|
826
917
|
"is deprecated and will be removed in a future Warp version.",
|
|
827
|
-
|
|
918
|
+
PendingDeprecationWarning,
|
|
828
919
|
stacklevel=2,
|
|
829
920
|
)
|
|
830
921
|
self._particle_radius.fill_(value)
|
|
@@ -891,6 +982,10 @@ class ModelBuilder:
|
|
|
891
982
|
default_tri_drag = 0.0
|
|
892
983
|
default_tri_lift = 0.0
|
|
893
984
|
|
|
985
|
+
# Default distance constraint properties
|
|
986
|
+
default_spring_ke = 100.0
|
|
987
|
+
default_spring_kd = 0.0
|
|
988
|
+
|
|
894
989
|
# Default edge bending properties
|
|
895
990
|
default_edge_ke = 100.0
|
|
896
991
|
default_edge_kd = 0.0
|
|
@@ -919,6 +1014,7 @@ class ModelBuilder:
|
|
|
919
1014
|
self.particle_mass = []
|
|
920
1015
|
self.particle_radius = []
|
|
921
1016
|
self.particle_flags = []
|
|
1017
|
+
self.particle_max_velocity = 1e5
|
|
922
1018
|
|
|
923
1019
|
# shapes (each shape has an entry in these arrays)
|
|
924
1020
|
# transform from shape to body
|
|
@@ -1034,8 +1130,8 @@ class ModelBuilder:
|
|
|
1034
1130
|
self.joint_coord_count = 0
|
|
1035
1131
|
self.joint_axis_total_count = 0
|
|
1036
1132
|
|
|
1037
|
-
self.up_vector = up_vector
|
|
1038
|
-
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)))
|
|
1039
1135
|
self.gravity = gravity
|
|
1040
1136
|
# indicates whether a ground plane has been created
|
|
1041
1137
|
self._ground_created = False
|
|
@@ -1126,15 +1222,25 @@ class ModelBuilder:
|
|
|
1126
1222
|
"""Copies a rigid articulation from `articulation`, another `ModelBuilder`.
|
|
1127
1223
|
|
|
1128
1224
|
Args:
|
|
1129
|
-
articulation: a model builder to add rigid articulation from.
|
|
1130
|
-
xform: offset transform applied to root bodies.
|
|
1131
|
-
update_num_env_count: if True, the number of environments is incremented by 1.
|
|
1132
|
-
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.
|
|
1133
1229
|
"""
|
|
1134
1230
|
|
|
1135
1231
|
start_body_idx = self.body_count
|
|
1136
1232
|
start_shape_idx = self.shape_count
|
|
1137
|
-
|
|
1233
|
+
for s, b in enumerate(articulation.shape_body):
|
|
1234
|
+
if b > -1:
|
|
1235
|
+
new_b = b + start_body_idx
|
|
1236
|
+
self.shape_body.append(new_b)
|
|
1237
|
+
self.shape_transform.append(articulation.shape_transform[s])
|
|
1238
|
+
else:
|
|
1239
|
+
self.shape_body.append(-1)
|
|
1240
|
+
# apply offset transform to root bodies
|
|
1241
|
+
if xform is not None:
|
|
1242
|
+
self.shape_transform.append(xform * articulation.shape_transform[s])
|
|
1243
|
+
|
|
1138
1244
|
for b, shapes in articulation.body_shapes.items():
|
|
1139
1245
|
self.body_shapes[b + start_body_idx] = [s + start_shape_idx for s in shapes]
|
|
1140
1246
|
|
|
@@ -1227,7 +1333,6 @@ class ModelBuilder:
|
|
|
1227
1333
|
"joint_target_kd",
|
|
1228
1334
|
"joint_linear_compliance",
|
|
1229
1335
|
"joint_angular_compliance",
|
|
1230
|
-
"shape_transform",
|
|
1231
1336
|
"shape_geo_type",
|
|
1232
1337
|
"shape_geo_scale",
|
|
1233
1338
|
"shape_geo_src",
|
|
@@ -1260,8 +1365,8 @@ class ModelBuilder:
|
|
|
1260
1365
|
self,
|
|
1261
1366
|
origin: Transform = wp.transform(),
|
|
1262
1367
|
armature: float = 0.0,
|
|
1263
|
-
com: Vec3 =
|
|
1264
|
-
I_m: Mat33 =
|
|
1368
|
+
com: Vec3 = wp.vec3(),
|
|
1369
|
+
I_m: Mat33 = wp.mat33(),
|
|
1265
1370
|
m: float = 0.0,
|
|
1266
1371
|
name: str = None,
|
|
1267
1372
|
) -> int:
|
|
@@ -1286,7 +1391,7 @@ class ModelBuilder:
|
|
|
1286
1391
|
body_id = len(self.body_mass)
|
|
1287
1392
|
|
|
1288
1393
|
# body data
|
|
1289
|
-
inertia = I_m + np.eye(3) * armature
|
|
1394
|
+
inertia = I_m + wp.mat33(np.eye(3)) * armature
|
|
1290
1395
|
self.body_inertia.append(inertia)
|
|
1291
1396
|
self.body_mass.append(m)
|
|
1292
1397
|
self.body_com.append(com)
|
|
@@ -1296,8 +1401,8 @@ class ModelBuilder:
|
|
|
1296
1401
|
else:
|
|
1297
1402
|
self.body_inv_mass.append(0.0)
|
|
1298
1403
|
|
|
1299
|
-
if
|
|
1300
|
-
self.body_inv_inertia.append(
|
|
1404
|
+
if any(x for x in inertia):
|
|
1405
|
+
self.body_inv_inertia.append(wp.inverse(inertia))
|
|
1301
1406
|
else:
|
|
1302
1407
|
self.body_inv_inertia.append(inertia)
|
|
1303
1408
|
|
|
@@ -1323,6 +1428,29 @@ class ModelBuilder:
|
|
|
1323
1428
|
collision_filter_parent: bool = True,
|
|
1324
1429
|
enabled: bool = True,
|
|
1325
1430
|
) -> int:
|
|
1431
|
+
"""
|
|
1432
|
+
Generic method to add any type of joint to this ModelBuilder.
|
|
1433
|
+
|
|
1434
|
+
Args:
|
|
1435
|
+
joint_type: The type of joint to add (see `Joint types`_)
|
|
1436
|
+
parent: The index of the parent body (-1 is the world)
|
|
1437
|
+
child: The index of the child body
|
|
1438
|
+
linear_axes: The linear axes (see :class:`JointAxis`) of the joint
|
|
1439
|
+
angular_axes: The angular axes (see :class:`JointAxis`) of the joint
|
|
1440
|
+
name: The name of the joint
|
|
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
|
|
1443
|
+
linear_compliance: The linear compliance of the joint
|
|
1444
|
+
angular_compliance: The angular compliance of the joint
|
|
1445
|
+
collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
|
|
1446
|
+
enabled: Whether the joint is enabled
|
|
1447
|
+
|
|
1448
|
+
Returns:
|
|
1449
|
+
The index of the added joint
|
|
1450
|
+
"""
|
|
1451
|
+
if len(self.articulation_start) == 0:
|
|
1452
|
+
# automatically add an articulation if none exists
|
|
1453
|
+
self.add_articulation()
|
|
1326
1454
|
self.joint_type.append(joint_type)
|
|
1327
1455
|
self.joint_parent.append(parent)
|
|
1328
1456
|
if child not in self.joint_parents:
|
|
@@ -1330,8 +1458,8 @@ class ModelBuilder:
|
|
|
1330
1458
|
else:
|
|
1331
1459
|
self.joint_parents[child].append(parent)
|
|
1332
1460
|
self.joint_child.append(child)
|
|
1333
|
-
self.joint_X_p.append(
|
|
1334
|
-
self.joint_X_c.append(
|
|
1461
|
+
self.joint_X_p.append(wp.transform(parent_xform))
|
|
1462
|
+
self.joint_X_c.append(wp.transform(child_xform))
|
|
1335
1463
|
self.joint_name.append(name or f"joint {self.joint_count}")
|
|
1336
1464
|
self.joint_axis_start.append(len(self.joint_axis))
|
|
1337
1465
|
self.joint_axis_dim.append((len(linear_axes), len(angular_axes)))
|
|
@@ -1341,7 +1469,7 @@ class ModelBuilder:
|
|
|
1341
1469
|
self.joint_angular_compliance.append(angular_compliance)
|
|
1342
1470
|
self.joint_enabled.append(enabled)
|
|
1343
1471
|
|
|
1344
|
-
|
|
1472
|
+
def add_axis_dim(dim):
|
|
1345
1473
|
self.joint_axis.append(dim.axis)
|
|
1346
1474
|
self.joint_axis_mode.append(dim.mode)
|
|
1347
1475
|
self.joint_target.append(dim.target)
|
|
@@ -1349,18 +1477,21 @@ class ModelBuilder:
|
|
|
1349
1477
|
self.joint_target_kd.append(dim.target_kd)
|
|
1350
1478
|
self.joint_limit_ke.append(dim.limit_ke)
|
|
1351
1479
|
self.joint_limit_kd.append(dim.limit_kd)
|
|
1352
|
-
|
|
1353
|
-
|
|
1480
|
+
if np.isfinite(dim.limit_lower):
|
|
1481
|
+
self.joint_limit_lower.append(dim.limit_lower)
|
|
1482
|
+
else:
|
|
1483
|
+
self.joint_limit_lower.append(-1e6)
|
|
1484
|
+
if np.isfinite(dim.limit_upper):
|
|
1485
|
+
self.joint_limit_upper.append(dim.limit_upper)
|
|
1486
|
+
else:
|
|
1487
|
+
self.joint_limit_upper.append(1e6)
|
|
1488
|
+
# self.joint_limit_lower.append(dim.limit_lower)
|
|
1489
|
+
# self.joint_limit_upper.append(dim.limit_upper)
|
|
1490
|
+
|
|
1491
|
+
for dim in linear_axes:
|
|
1492
|
+
add_axis_dim(dim)
|
|
1354
1493
|
for dim in angular_axes:
|
|
1355
|
-
|
|
1356
|
-
self.joint_axis_mode.append(dim.mode)
|
|
1357
|
-
self.joint_target.append(dim.target)
|
|
1358
|
-
self.joint_target_ke.append(dim.target_ke)
|
|
1359
|
-
self.joint_target_kd.append(dim.target_kd)
|
|
1360
|
-
self.joint_limit_ke.append(dim.limit_ke)
|
|
1361
|
-
self.joint_limit_kd.append(dim.limit_kd)
|
|
1362
|
-
self.joint_limit_lower.append(dim.limit_lower)
|
|
1363
|
-
self.joint_limit_upper.append(dim.limit_upper)
|
|
1494
|
+
add_axis_dim(dim)
|
|
1364
1495
|
|
|
1365
1496
|
if joint_type == JOINT_PRISMATIC:
|
|
1366
1497
|
dof_count = 1
|
|
@@ -1371,7 +1502,7 @@ class ModelBuilder:
|
|
|
1371
1502
|
elif joint_type == JOINT_BALL:
|
|
1372
1503
|
dof_count = 3
|
|
1373
1504
|
coord_count = 4
|
|
1374
|
-
elif joint_type == JOINT_FREE:
|
|
1505
|
+
elif joint_type == JOINT_FREE or joint_type == JOINT_DISTANCE:
|
|
1375
1506
|
dof_count = 6
|
|
1376
1507
|
coord_count = 7
|
|
1377
1508
|
elif joint_type == JOINT_FIXED:
|
|
@@ -1383,10 +1514,6 @@ class ModelBuilder:
|
|
|
1383
1514
|
elif joint_type == JOINT_COMPOUND:
|
|
1384
1515
|
dof_count = 3
|
|
1385
1516
|
coord_count = 3
|
|
1386
|
-
elif joint_type == JOINT_DISTANCE:
|
|
1387
|
-
# todo use free joint dofs?
|
|
1388
|
-
dof_count = 0
|
|
1389
|
-
coord_count = 0
|
|
1390
1517
|
elif joint_type == JOINT_D6:
|
|
1391
1518
|
dof_count = len(linear_axes) + len(angular_axes)
|
|
1392
1519
|
coord_count = dof_count
|
|
@@ -1398,7 +1525,7 @@ class ModelBuilder:
|
|
|
1398
1525
|
self.joint_qd.append(0.0)
|
|
1399
1526
|
self.joint_act.append(0.0)
|
|
1400
1527
|
|
|
1401
|
-
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:
|
|
1402
1529
|
# ensure that a valid quaternion is used for the angular dofs
|
|
1403
1530
|
self.joint_q[-1] = 1.0
|
|
1404
1531
|
|
|
@@ -1436,14 +1563,14 @@ class ModelBuilder:
|
|
|
1436
1563
|
collision_filter_parent: bool = True,
|
|
1437
1564
|
enabled: bool = True,
|
|
1438
1565
|
) -> int:
|
|
1439
|
-
"""Adds a revolute joint to the model
|
|
1566
|
+
"""Adds a revolute (hinge) joint to the model. It has one degree of freedom.
|
|
1440
1567
|
|
|
1441
1568
|
Args:
|
|
1442
1569
|
parent: The index of the parent body
|
|
1443
1570
|
child: The index of the child body
|
|
1444
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1445
|
-
child_xform: The transform of the joint in the child body's local frame
|
|
1446
|
-
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
|
|
1447
1574
|
target: The target angle (in radians) of the joint
|
|
1448
1575
|
target_ke: The stiffness of the joint target
|
|
1449
1576
|
target_kd: The damping of the joint target
|
|
@@ -1458,7 +1585,7 @@ class ModelBuilder:
|
|
|
1458
1585
|
enabled: Whether the joint is enabled
|
|
1459
1586
|
|
|
1460
1587
|
Returns:
|
|
1461
|
-
The index of the
|
|
1588
|
+
The index of the added joint
|
|
1462
1589
|
|
|
1463
1590
|
"""
|
|
1464
1591
|
ax = JointAxis(
|
|
@@ -1507,14 +1634,14 @@ class ModelBuilder:
|
|
|
1507
1634
|
collision_filter_parent: bool = True,
|
|
1508
1635
|
enabled: bool = True,
|
|
1509
1636
|
) -> int:
|
|
1510
|
-
"""Adds a prismatic joint to the model
|
|
1637
|
+
"""Adds a prismatic (sliding) joint to the model. It has one degree of freedom.
|
|
1511
1638
|
|
|
1512
1639
|
Args:
|
|
1513
1640
|
parent: The index of the parent body
|
|
1514
1641
|
child: The index of the child body
|
|
1515
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1516
|
-
child_xform: The transform of the joint in the child body's local frame
|
|
1517
|
-
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
|
|
1518
1645
|
target: The target position of the joint
|
|
1519
1646
|
target_ke: The stiffness of the joint target
|
|
1520
1647
|
target_kd: The damping of the joint target
|
|
@@ -1529,7 +1656,7 @@ class ModelBuilder:
|
|
|
1529
1656
|
enabled: Whether the joint is enabled
|
|
1530
1657
|
|
|
1531
1658
|
Returns:
|
|
1532
|
-
The index of the
|
|
1659
|
+
The index of the added joint
|
|
1533
1660
|
|
|
1534
1661
|
"""
|
|
1535
1662
|
ax = JointAxis(
|
|
@@ -1569,13 +1696,13 @@ class ModelBuilder:
|
|
|
1569
1696
|
collision_filter_parent: bool = True,
|
|
1570
1697
|
enabled: bool = True,
|
|
1571
1698
|
) -> int:
|
|
1572
|
-
"""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.
|
|
1573
1700
|
|
|
1574
1701
|
Args:
|
|
1575
1702
|
parent: The index of the parent body
|
|
1576
1703
|
child: The index of the child body
|
|
1577
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1578
|
-
|
|
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
|
|
1579
1706
|
linear_compliance: The linear compliance of the joint
|
|
1580
1707
|
angular_compliance: The angular compliance of the joint
|
|
1581
1708
|
name: The name of the joint
|
|
@@ -1583,7 +1710,7 @@ class ModelBuilder:
|
|
|
1583
1710
|
enabled: Whether the joint is enabled
|
|
1584
1711
|
|
|
1585
1712
|
Returns:
|
|
1586
|
-
The index of the
|
|
1713
|
+
The index of the added joint
|
|
1587
1714
|
|
|
1588
1715
|
"""
|
|
1589
1716
|
return self.add_joint(
|
|
@@ -1611,13 +1738,14 @@ class ModelBuilder:
|
|
|
1611
1738
|
collision_filter_parent: bool = True,
|
|
1612
1739
|
enabled: bool = True,
|
|
1613
1740
|
) -> int:
|
|
1614
|
-
"""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.
|
|
1615
1743
|
|
|
1616
1744
|
Args:
|
|
1617
1745
|
parent: The index of the parent body
|
|
1618
1746
|
child: The index of the child body
|
|
1619
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1620
|
-
|
|
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
|
|
1621
1749
|
linear_compliance: The linear compliance of the joint
|
|
1622
1750
|
angular_compliance: The angular compliance of the joint
|
|
1623
1751
|
name: The name of the joint
|
|
@@ -1625,7 +1753,7 @@ class ModelBuilder:
|
|
|
1625
1753
|
enabled: Whether the joint is enabled
|
|
1626
1754
|
|
|
1627
1755
|
Returns:
|
|
1628
|
-
The index of the
|
|
1756
|
+
The index of the added joint
|
|
1629
1757
|
|
|
1630
1758
|
"""
|
|
1631
1759
|
return self.add_joint(
|
|
@@ -1651,19 +1779,20 @@ class ModelBuilder:
|
|
|
1651
1779
|
collision_filter_parent: bool = True,
|
|
1652
1780
|
enabled: bool = True,
|
|
1653
1781
|
) -> int:
|
|
1654
|
-
"""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).
|
|
1655
1784
|
|
|
1656
1785
|
Args:
|
|
1657
|
-
parent: The index of the parent body
|
|
1658
1786
|
child: The index of the child body
|
|
1659
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1660
|
-
|
|
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)
|
|
1661
1790
|
name: The name of the joint
|
|
1662
1791
|
collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
|
|
1663
1792
|
enabled: Whether the joint is enabled
|
|
1664
1793
|
|
|
1665
1794
|
Returns:
|
|
1666
|
-
The index of the
|
|
1795
|
+
The index of the added joint
|
|
1667
1796
|
|
|
1668
1797
|
"""
|
|
1669
1798
|
return self.add_joint(
|
|
@@ -1689,13 +1818,14 @@ class ModelBuilder:
|
|
|
1689
1818
|
collision_filter_parent: bool = True,
|
|
1690
1819
|
enabled: bool = True,
|
|
1691
1820
|
) -> int:
|
|
1692
|
-
"""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).
|
|
1693
1823
|
|
|
1694
1824
|
Args:
|
|
1695
1825
|
parent: The index of the parent body
|
|
1696
1826
|
child: The index of the child body
|
|
1697
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1698
|
-
|
|
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
|
|
1699
1829
|
min_distance: The minimum distance between the bodies (no limit if negative)
|
|
1700
1830
|
max_distance: The maximum distance between the bodies (no limit if negative)
|
|
1701
1831
|
compliance: The compliance of the joint
|
|
@@ -1703,7 +1833,9 @@ class ModelBuilder:
|
|
|
1703
1833
|
enabled: Whether the joint is enabled
|
|
1704
1834
|
|
|
1705
1835
|
Returns:
|
|
1706
|
-
The index of the
|
|
1836
|
+
The index of the added joint
|
|
1837
|
+
|
|
1838
|
+
.. note:: Distance joints are currently only supported in the :class:`XPBDIntegrator` at the moment.
|
|
1707
1839
|
|
|
1708
1840
|
"""
|
|
1709
1841
|
ax = JointAxis(
|
|
@@ -1737,15 +1869,15 @@ class ModelBuilder:
|
|
|
1737
1869
|
collision_filter_parent: bool = True,
|
|
1738
1870
|
enabled: bool = True,
|
|
1739
1871
|
) -> int:
|
|
1740
|
-
"""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.
|
|
1741
1873
|
|
|
1742
1874
|
Args:
|
|
1743
1875
|
parent: The index of the parent body
|
|
1744
1876
|
child: The index of the child body
|
|
1745
|
-
axis_0: The first axis of the joint
|
|
1746
|
-
axis_1: The second axis of the joint
|
|
1747
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1748
|
-
|
|
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
|
|
1749
1881
|
linear_compliance: The linear compliance of the joint
|
|
1750
1882
|
angular_compliance: The angular compliance of the joint
|
|
1751
1883
|
name: The name of the joint
|
|
@@ -1753,14 +1885,14 @@ class ModelBuilder:
|
|
|
1753
1885
|
enabled: Whether the joint is enabled
|
|
1754
1886
|
|
|
1755
1887
|
Returns:
|
|
1756
|
-
The index of the
|
|
1888
|
+
The index of the added joint
|
|
1757
1889
|
|
|
1758
1890
|
"""
|
|
1759
1891
|
return self.add_joint(
|
|
1760
1892
|
JOINT_UNIVERSAL,
|
|
1761
1893
|
parent,
|
|
1762
1894
|
child,
|
|
1763
|
-
angular_axes=[axis_0, axis_1],
|
|
1895
|
+
angular_axes=[JointAxis(axis_0), JointAxis(axis_1)],
|
|
1764
1896
|
parent_xform=parent_xform,
|
|
1765
1897
|
child_xform=child_xform,
|
|
1766
1898
|
linear_compliance=linear_compliance,
|
|
@@ -1783,29 +1915,32 @@ class ModelBuilder:
|
|
|
1783
1915
|
collision_filter_parent: bool = True,
|
|
1784
1916
|
enabled: bool = True,
|
|
1785
1917
|
) -> int:
|
|
1786
|
-
"""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`.
|
|
1787
1922
|
|
|
1788
1923
|
Args:
|
|
1789
1924
|
parent: The index of the parent body
|
|
1790
1925
|
child: The index of the child body
|
|
1791
|
-
axis_0: The first axis of the joint
|
|
1792
|
-
axis_1: The second axis of the joint
|
|
1793
|
-
axis_2: The third axis of the joint
|
|
1794
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1795
|
-
|
|
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
|
|
1796
1931
|
name: The name of the joint
|
|
1797
1932
|
collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
|
|
1798
1933
|
enabled: Whether the joint is enabled
|
|
1799
1934
|
|
|
1800
1935
|
Returns:
|
|
1801
|
-
The index of the
|
|
1936
|
+
The index of the added joint
|
|
1802
1937
|
|
|
1803
1938
|
"""
|
|
1804
1939
|
return self.add_joint(
|
|
1805
1940
|
JOINT_COMPOUND,
|
|
1806
1941
|
parent,
|
|
1807
1942
|
child,
|
|
1808
|
-
angular_axes=[axis_0, axis_1, axis_2],
|
|
1943
|
+
angular_axes=[JointAxis(axis_0), JointAxis(axis_1), JointAxis(axis_2)],
|
|
1809
1944
|
parent_xform=parent_xform,
|
|
1810
1945
|
child_xform=child_xform,
|
|
1811
1946
|
name=name,
|
|
@@ -1827,7 +1962,7 @@ class ModelBuilder:
|
|
|
1827
1962
|
collision_filter_parent: bool = True,
|
|
1828
1963
|
enabled: bool = True,
|
|
1829
1964
|
):
|
|
1830
|
-
"""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.
|
|
1831
1966
|
|
|
1832
1967
|
Args:
|
|
1833
1968
|
parent: The index of the parent body
|
|
@@ -1835,15 +1970,15 @@ class ModelBuilder:
|
|
|
1835
1970
|
linear_axes: A list of linear axes
|
|
1836
1971
|
angular_axes: A list of angular axes
|
|
1837
1972
|
name: The name of the joint
|
|
1838
|
-
parent_xform: The transform of the joint in the parent body's local frame
|
|
1839
|
-
|
|
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
|
|
1840
1975
|
linear_compliance: The linear compliance of the joint
|
|
1841
1976
|
angular_compliance: The angular compliance of the joint
|
|
1842
1977
|
collision_filter_parent: Whether to filter collisions between shapes of the parent and child bodies
|
|
1843
1978
|
enabled: Whether the joint is enabled
|
|
1844
1979
|
|
|
1845
1980
|
Returns:
|
|
1846
|
-
The index of the
|
|
1981
|
+
The index of the added joint
|
|
1847
1982
|
|
|
1848
1983
|
"""
|
|
1849
1984
|
return self.add_joint(
|
|
@@ -1852,8 +1987,8 @@ class ModelBuilder:
|
|
|
1852
1987
|
child,
|
|
1853
1988
|
parent_xform=parent_xform,
|
|
1854
1989
|
child_xform=child_xform,
|
|
1855
|
-
linear_axes=linear_axes,
|
|
1856
|
-
angular_axes=angular_axes,
|
|
1990
|
+
linear_axes=[JointAxis(a) for a in linear_axes],
|
|
1991
|
+
angular_axes=[JointAxis(a) for a in angular_axes],
|
|
1857
1992
|
linear_compliance=linear_compliance,
|
|
1858
1993
|
angular_compliance=angular_compliance,
|
|
1859
1994
|
name=name,
|
|
@@ -1861,11 +1996,257 @@ class ModelBuilder:
|
|
|
1861
1996
|
enabled=enabled,
|
|
1862
1997
|
)
|
|
1863
1998
|
|
|
1999
|
+
def collapse_fixed_joints(self, verbose=wp.config.verbose):
|
|
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."""
|
|
2001
|
+
|
|
2002
|
+
body_data = {}
|
|
2003
|
+
body_children = {-1: []}
|
|
2004
|
+
visited = {}
|
|
2005
|
+
for i in range(self.body_count):
|
|
2006
|
+
name = self.body_name[i]
|
|
2007
|
+
body_data[i] = {
|
|
2008
|
+
"shapes": self.body_shapes[i],
|
|
2009
|
+
"q": self.body_q[i],
|
|
2010
|
+
"qd": self.body_qd[i],
|
|
2011
|
+
"mass": self.body_mass[i],
|
|
2012
|
+
"inertia": self.body_inertia[i],
|
|
2013
|
+
"inv_mass": self.body_inv_mass[i],
|
|
2014
|
+
"inv_inertia": self.body_inv_inertia[i],
|
|
2015
|
+
"com": self.body_com[i],
|
|
2016
|
+
"name": name,
|
|
2017
|
+
"original_id": i,
|
|
2018
|
+
}
|
|
2019
|
+
visited[i] = False
|
|
2020
|
+
body_children[i] = []
|
|
2021
|
+
|
|
2022
|
+
joint_data = {}
|
|
2023
|
+
for i in range(self.joint_count):
|
|
2024
|
+
name = self.joint_name[i]
|
|
2025
|
+
parent = self.joint_parent[i]
|
|
2026
|
+
child = self.joint_child[i]
|
|
2027
|
+
body_children[parent].append(child)
|
|
2028
|
+
|
|
2029
|
+
q_start = self.joint_q_start[i]
|
|
2030
|
+
qd_start = self.joint_qd_start[i]
|
|
2031
|
+
if i < self.joint_count - 1:
|
|
2032
|
+
q_dim = self.joint_q_start[i + 1] - q_start
|
|
2033
|
+
qd_dim = self.joint_qd_start[i + 1] - qd_start
|
|
2034
|
+
else:
|
|
2035
|
+
q_dim = len(self.joint_q) - q_start
|
|
2036
|
+
qd_dim = len(self.joint_qd) - qd_start
|
|
2037
|
+
|
|
2038
|
+
data = {
|
|
2039
|
+
"type": self.joint_type[i],
|
|
2040
|
+
# 'armature': self.joint_armature[i],
|
|
2041
|
+
"q": self.joint_q[q_start : q_start + q_dim],
|
|
2042
|
+
"qd": self.joint_qd[qd_start : qd_start + qd_dim],
|
|
2043
|
+
"act": self.joint_act[qd_start : qd_start + qd_dim],
|
|
2044
|
+
"q_start": q_start,
|
|
2045
|
+
"qd_start": qd_start,
|
|
2046
|
+
"linear_compliance": self.joint_linear_compliance[i],
|
|
2047
|
+
"angular_compliance": self.joint_angular_compliance[i],
|
|
2048
|
+
"name": name,
|
|
2049
|
+
"parent_xform": wp.transform_expand(self.joint_X_p[i]),
|
|
2050
|
+
"child_xform": wp.transform_expand(self.joint_X_c[i]),
|
|
2051
|
+
"enabled": self.joint_enabled[i],
|
|
2052
|
+
"axes": [],
|
|
2053
|
+
"axis_dim": self.joint_axis_dim[i],
|
|
2054
|
+
"parent": parent,
|
|
2055
|
+
"child": child,
|
|
2056
|
+
"original_id": i,
|
|
2057
|
+
}
|
|
2058
|
+
num_lin_axes, num_ang_axes = self.joint_axis_dim[i]
|
|
2059
|
+
start_ax = self.joint_axis_start[i]
|
|
2060
|
+
for j in range(start_ax, start_ax + num_lin_axes + num_ang_axes):
|
|
2061
|
+
data["axes"].append(
|
|
2062
|
+
{
|
|
2063
|
+
"axis": self.joint_axis[j],
|
|
2064
|
+
"axis_mode": self.joint_axis_mode[j],
|
|
2065
|
+
"target": self.joint_target[j],
|
|
2066
|
+
"target_ke": self.joint_target_ke[j],
|
|
2067
|
+
"target_kd": self.joint_target_kd[j],
|
|
2068
|
+
"limit_ke": self.joint_limit_ke[j],
|
|
2069
|
+
"limit_kd": self.joint_limit_kd[j],
|
|
2070
|
+
"limit_lower": self.joint_limit_lower[j],
|
|
2071
|
+
"limit_upper": self.joint_limit_upper[j],
|
|
2072
|
+
}
|
|
2073
|
+
)
|
|
2074
|
+
|
|
2075
|
+
joint_data[(parent, child)] = data
|
|
2076
|
+
|
|
2077
|
+
# sort body children so we traverse the tree in the same order as the bodies are listed
|
|
2078
|
+
for children in body_children.values():
|
|
2079
|
+
children.sort(key=lambda x: body_data[x]["original_id"])
|
|
2080
|
+
|
|
2081
|
+
retained_joints = []
|
|
2082
|
+
retained_bodies = []
|
|
2083
|
+
body_remap = {-1: -1}
|
|
2084
|
+
|
|
2085
|
+
# depth first search over the joint graph
|
|
2086
|
+
def dfs(parent_body: int, child_body: int, incoming_xform: wp.transform, last_dynamic_body: int):
|
|
2087
|
+
nonlocal visited
|
|
2088
|
+
nonlocal retained_joints
|
|
2089
|
+
nonlocal retained_bodies
|
|
2090
|
+
nonlocal body_data
|
|
2091
|
+
nonlocal body_remap
|
|
2092
|
+
|
|
2093
|
+
joint = joint_data[(parent_body, child_body)]
|
|
2094
|
+
if joint["type"] == JOINT_FIXED:
|
|
2095
|
+
joint_xform = joint["parent_xform"] * wp.transform_inverse(joint["child_xform"])
|
|
2096
|
+
incoming_xform = incoming_xform * joint_xform
|
|
2097
|
+
parent_name = self.body_name[parent_body] if parent_body > -1 else "world"
|
|
2098
|
+
child_name = self.body_name[child_body]
|
|
2099
|
+
last_dynamic_body_name = self.body_name[last_dynamic_body] if last_dynamic_body > -1 else "world"
|
|
2100
|
+
if verbose:
|
|
2101
|
+
print(
|
|
2102
|
+
f'Remove fixed joint {joint["name"]} between {parent_name} and {child_name}, '
|
|
2103
|
+
f"merging {child_name} into {last_dynamic_body_name}"
|
|
2104
|
+
)
|
|
2105
|
+
child_id = body_data[child_body]["original_id"]
|
|
2106
|
+
for shape in self.body_shapes[child_id]:
|
|
2107
|
+
self.shape_transform[shape] = incoming_xform * self.shape_transform[shape]
|
|
2108
|
+
if verbose:
|
|
2109
|
+
print(
|
|
2110
|
+
f" Shape {shape} moved to body {last_dynamic_body_name} with transform {self.shape_transform[shape]}"
|
|
2111
|
+
)
|
|
2112
|
+
if last_dynamic_body > -1:
|
|
2113
|
+
self.shape_body[shape] = body_data[last_dynamic_body]["id"]
|
|
2114
|
+
# add inertia to last_dynamic_body
|
|
2115
|
+
m = body_data[child_body]["mass"]
|
|
2116
|
+
com = body_data[child_body]["com"]
|
|
2117
|
+
inertia = body_data[child_body]["inertia"]
|
|
2118
|
+
body_data[last_dynamic_body]["inertia"] += wp.sim.transform_inertia(
|
|
2119
|
+
m, inertia, incoming_xform.p, incoming_xform.q
|
|
2120
|
+
)
|
|
2121
|
+
body_data[last_dynamic_body]["mass"] += m
|
|
2122
|
+
source_m = body_data[last_dynamic_body]["mass"]
|
|
2123
|
+
source_com = body_data[last_dynamic_body]["com"]
|
|
2124
|
+
body_data[last_dynamic_body]["com"] = (m * com + source_m * source_com) / (m + source_m)
|
|
2125
|
+
body_data[last_dynamic_body]["shapes"].append(shape)
|
|
2126
|
+
# indicate to recompute inverse mass, inertia for this body
|
|
2127
|
+
body_data[last_dynamic_body]["inv_mass"] = None
|
|
2128
|
+
else:
|
|
2129
|
+
self.shape_body[shape] = -1
|
|
2130
|
+
else:
|
|
2131
|
+
joint["parent_xform"] = incoming_xform * joint["parent_xform"]
|
|
2132
|
+
joint["parent"] = last_dynamic_body
|
|
2133
|
+
last_dynamic_body = child_body
|
|
2134
|
+
incoming_xform = wp.transform()
|
|
2135
|
+
retained_joints.append(joint)
|
|
2136
|
+
new_id = len(retained_bodies)
|
|
2137
|
+
body_data[child_body]["id"] = new_id
|
|
2138
|
+
retained_bodies.append(child_body)
|
|
2139
|
+
for shape in body_data[child_body]["shapes"]:
|
|
2140
|
+
self.shape_body[shape] = new_id
|
|
2141
|
+
|
|
2142
|
+
visited[parent_body] = True
|
|
2143
|
+
if visited[child_body] or child_body not in body_children:
|
|
2144
|
+
return
|
|
2145
|
+
for child in body_children[child_body]:
|
|
2146
|
+
if not visited[child]:
|
|
2147
|
+
dfs(child_body, child, incoming_xform, last_dynamic_body)
|
|
2148
|
+
|
|
2149
|
+
for body in body_children[-1]:
|
|
2150
|
+
if not visited[body]:
|
|
2151
|
+
dfs(-1, body, wp.transform(), -1)
|
|
2152
|
+
|
|
2153
|
+
# repopulate the model
|
|
2154
|
+
self.body_name.clear()
|
|
2155
|
+
self.body_q.clear()
|
|
2156
|
+
self.body_qd.clear()
|
|
2157
|
+
self.body_mass.clear()
|
|
2158
|
+
self.body_inertia.clear()
|
|
2159
|
+
self.body_com.clear()
|
|
2160
|
+
self.body_inv_mass.clear()
|
|
2161
|
+
self.body_inv_inertia.clear()
|
|
2162
|
+
self.body_shapes.clear()
|
|
2163
|
+
for i in retained_bodies:
|
|
2164
|
+
body = body_data[i]
|
|
2165
|
+
new_id = len(self.body_name)
|
|
2166
|
+
body_remap[body["original_id"]] = new_id
|
|
2167
|
+
self.body_name.append(body["name"])
|
|
2168
|
+
self.body_q.append(list(body["q"]))
|
|
2169
|
+
self.body_qd.append(list(body["qd"]))
|
|
2170
|
+
m = body["mass"]
|
|
2171
|
+
inertia = body["inertia"]
|
|
2172
|
+
self.body_mass.append(m)
|
|
2173
|
+
self.body_inertia.append(inertia)
|
|
2174
|
+
self.body_com.append(body["com"])
|
|
2175
|
+
if body["inv_mass"] is None:
|
|
2176
|
+
# recompute inverse mass and inertia
|
|
2177
|
+
if m > 0.0:
|
|
2178
|
+
self.body_inv_mass.append(1.0 / m)
|
|
2179
|
+
self.body_inv_inertia.append(np.linalg.inv(inertia))
|
|
2180
|
+
else:
|
|
2181
|
+
self.body_inv_mass.append(0.0)
|
|
2182
|
+
self.body_inv_inertia.append(np.zeros((3, 3)))
|
|
2183
|
+
else:
|
|
2184
|
+
self.body_inv_mass.append(body["inv_mass"])
|
|
2185
|
+
self.body_inv_inertia.append(body["inv_inertia"])
|
|
2186
|
+
self.body_shapes[new_id] = body["shapes"]
|
|
2187
|
+
body_remap[body["original_id"]] = new_id
|
|
2188
|
+
|
|
2189
|
+
# sort joints so they appear in the same order as before
|
|
2190
|
+
retained_joints.sort(key=lambda x: x["original_id"])
|
|
2191
|
+
|
|
2192
|
+
self.joint_name.clear()
|
|
2193
|
+
self.joint_type.clear()
|
|
2194
|
+
self.joint_parent.clear()
|
|
2195
|
+
self.joint_child.clear()
|
|
2196
|
+
self.joint_q.clear()
|
|
2197
|
+
self.joint_qd.clear()
|
|
2198
|
+
self.joint_q_start.clear()
|
|
2199
|
+
self.joint_qd_start.clear()
|
|
2200
|
+
self.joint_enabled.clear()
|
|
2201
|
+
self.joint_linear_compliance.clear()
|
|
2202
|
+
self.joint_angular_compliance.clear()
|
|
2203
|
+
self.joint_X_p.clear()
|
|
2204
|
+
self.joint_X_c.clear()
|
|
2205
|
+
self.joint_axis.clear()
|
|
2206
|
+
self.joint_axis_mode.clear()
|
|
2207
|
+
self.joint_target.clear()
|
|
2208
|
+
self.joint_target_ke.clear()
|
|
2209
|
+
self.joint_target_kd.clear()
|
|
2210
|
+
self.joint_limit_lower.clear()
|
|
2211
|
+
self.joint_limit_upper.clear()
|
|
2212
|
+
self.joint_limit_ke.clear()
|
|
2213
|
+
self.joint_limit_kd.clear()
|
|
2214
|
+
self.joint_axis_dim.clear()
|
|
2215
|
+
self.joint_axis_start.clear()
|
|
2216
|
+
self.joint_act.clear()
|
|
2217
|
+
for joint in retained_joints:
|
|
2218
|
+
self.joint_name.append(joint["name"])
|
|
2219
|
+
self.joint_type.append(joint["type"])
|
|
2220
|
+
self.joint_parent.append(body_remap[joint["parent"]])
|
|
2221
|
+
self.joint_child.append(body_remap[joint["child"]])
|
|
2222
|
+
self.joint_q_start.append(len(self.joint_q))
|
|
2223
|
+
self.joint_qd_start.append(len(self.joint_qd))
|
|
2224
|
+
self.joint_q.extend(joint["q"])
|
|
2225
|
+
self.joint_qd.extend(joint["qd"])
|
|
2226
|
+
self.joint_act.extend(joint["act"])
|
|
2227
|
+
self.joint_enabled.append(joint["enabled"])
|
|
2228
|
+
self.joint_linear_compliance.append(joint["linear_compliance"])
|
|
2229
|
+
self.joint_angular_compliance.append(joint["angular_compliance"])
|
|
2230
|
+
self.joint_X_p.append(list(joint["parent_xform"]))
|
|
2231
|
+
self.joint_X_c.append(list(joint["child_xform"]))
|
|
2232
|
+
self.joint_axis_dim.append(joint["axis_dim"])
|
|
2233
|
+
self.joint_axis_start.append(len(self.joint_axis))
|
|
2234
|
+
for axis in joint["axes"]:
|
|
2235
|
+
self.joint_axis.append(axis["axis"])
|
|
2236
|
+
self.joint_axis_mode.append(axis["axis_mode"])
|
|
2237
|
+
self.joint_target.append(axis["target"])
|
|
2238
|
+
self.joint_target_ke.append(axis["target_ke"])
|
|
2239
|
+
self.joint_target_kd.append(axis["target_kd"])
|
|
2240
|
+
self.joint_limit_lower.append(axis["limit_lower"])
|
|
2241
|
+
self.joint_limit_upper.append(axis["limit_upper"])
|
|
2242
|
+
self.joint_limit_ke.append(axis["limit_ke"])
|
|
2243
|
+
self.joint_limit_kd.append(axis["limit_kd"])
|
|
2244
|
+
|
|
1864
2245
|
# muscles
|
|
1865
2246
|
def add_muscle(
|
|
1866
2247
|
self, bodies: List[int], positions: List[Vec3], f0: float, lm: float, lt: float, lmax: float, pen: float
|
|
1867
2248
|
) -> float:
|
|
1868
|
-
"""Adds a muscle-tendon activation unit
|
|
2249
|
+
"""Adds a muscle-tendon activation unit.
|
|
1869
2250
|
|
|
1870
2251
|
Args:
|
|
1871
2252
|
bodies: A list of body indices for each waypoint
|
|
@@ -1878,6 +2259,8 @@ class ModelBuilder:
|
|
|
1878
2259
|
Returns:
|
|
1879
2260
|
The index of the muscle in the model
|
|
1880
2261
|
|
|
2262
|
+
.. note:: The simulation support for muscles is in progress and not yet fully functional.
|
|
2263
|
+
|
|
1881
2264
|
"""
|
|
1882
2265
|
|
|
1883
2266
|
n = len(bodies)
|
|
@@ -1913,7 +2296,7 @@ class ModelBuilder:
|
|
|
1913
2296
|
"""
|
|
1914
2297
|
Adds a plane collision shape.
|
|
1915
2298
|
If pos and rot are defined, the plane is assumed to have its normal as (0, 1, 0).
|
|
1916
|
-
Otherwise, the plane equation is used.
|
|
2299
|
+
Otherwise, the plane equation defined through the `plane` argument is used.
|
|
1917
2300
|
|
|
1918
2301
|
Args:
|
|
1919
2302
|
plane: The plane equation in form a*x + b*y + c*z + d = 0
|
|
@@ -1930,6 +2313,9 @@ class ModelBuilder:
|
|
|
1930
2313
|
thickness: The thickness of the plane (0 by default) for collision handling
|
|
1931
2314
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
1932
2315
|
|
|
2316
|
+
Returns:
|
|
2317
|
+
The index of the added shape
|
|
2318
|
+
|
|
1933
2319
|
"""
|
|
1934
2320
|
if pos is None or rot is None:
|
|
1935
2321
|
# compute position and rotation from plane equation
|
|
@@ -1944,7 +2330,7 @@ class ModelBuilder:
|
|
|
1944
2330
|
angle = np.arcsin(np.linalg.norm(c))
|
|
1945
2331
|
axis = c / np.linalg.norm(c)
|
|
1946
2332
|
rot = wp.quat_from_axis_angle(axis, angle)
|
|
1947
|
-
scale = (width, length, 0.0)
|
|
2333
|
+
scale = wp.vec3(width, length, 0.0)
|
|
1948
2334
|
|
|
1949
2335
|
return self._add_shape(
|
|
1950
2336
|
body,
|
|
@@ -1982,7 +2368,7 @@ class ModelBuilder:
|
|
|
1982
2368
|
"""Adds a sphere collision shape to a body.
|
|
1983
2369
|
|
|
1984
2370
|
Args:
|
|
1985
|
-
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)
|
|
1986
2372
|
pos: The location of the shape with respect to the parent frame
|
|
1987
2373
|
rot: The rotation of the shape with respect to the parent frame
|
|
1988
2374
|
radius: The radius of the sphere
|
|
@@ -1996,14 +2382,17 @@ class ModelBuilder:
|
|
|
1996
2382
|
thickness: Thickness to use for computing inertia of a hollow sphere, and for collision handling
|
|
1997
2383
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
1998
2384
|
|
|
2385
|
+
Returns:
|
|
2386
|
+
The index of the added shape
|
|
2387
|
+
|
|
1999
2388
|
"""
|
|
2000
2389
|
|
|
2001
2390
|
return self._add_shape(
|
|
2002
2391
|
body,
|
|
2003
|
-
pos,
|
|
2004
|
-
rot,
|
|
2392
|
+
wp.vec3(pos),
|
|
2393
|
+
wp.quat(rot),
|
|
2005
2394
|
GEO_SPHERE,
|
|
2006
|
-
(radius, 0.0, 0.0
|
|
2395
|
+
wp.vec3(radius, 0.0, 0.0),
|
|
2007
2396
|
None,
|
|
2008
2397
|
density,
|
|
2009
2398
|
ke,
|
|
@@ -2037,7 +2426,7 @@ class ModelBuilder:
|
|
|
2037
2426
|
"""Adds a box collision shape to a body.
|
|
2038
2427
|
|
|
2039
2428
|
Args:
|
|
2040
|
-
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)
|
|
2041
2430
|
pos: The location of the shape with respect to the parent frame
|
|
2042
2431
|
rot: The rotation of the shape with respect to the parent frame
|
|
2043
2432
|
hx: The half-extent along the x-axis
|
|
@@ -2053,14 +2442,17 @@ class ModelBuilder:
|
|
|
2053
2442
|
thickness: Thickness to use for computing inertia of a hollow box, and for collision handling
|
|
2054
2443
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
2055
2444
|
|
|
2445
|
+
Returns:
|
|
2446
|
+
The index of the added shape
|
|
2447
|
+
|
|
2056
2448
|
"""
|
|
2057
2449
|
|
|
2058
2450
|
return self._add_shape(
|
|
2059
2451
|
body,
|
|
2060
|
-
pos,
|
|
2061
|
-
rot,
|
|
2452
|
+
wp.vec3(pos),
|
|
2453
|
+
wp.quat(rot),
|
|
2062
2454
|
GEO_BOX,
|
|
2063
|
-
(hx, hy, hz
|
|
2455
|
+
wp.vec3(hx, hy, hz),
|
|
2064
2456
|
None,
|
|
2065
2457
|
density,
|
|
2066
2458
|
ke,
|
|
@@ -2094,7 +2486,7 @@ class ModelBuilder:
|
|
|
2094
2486
|
"""Adds a capsule collision shape to a body.
|
|
2095
2487
|
|
|
2096
2488
|
Args:
|
|
2097
|
-
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)
|
|
2098
2490
|
pos: The location of the shape with respect to the parent frame
|
|
2099
2491
|
rot: The rotation of the shape with respect to the parent frame
|
|
2100
2492
|
radius: The radius of the capsule
|
|
@@ -2110,21 +2502,24 @@ class ModelBuilder:
|
|
|
2110
2502
|
thickness: Thickness to use for computing inertia of a hollow capsule, and for collision handling
|
|
2111
2503
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
2112
2504
|
|
|
2505
|
+
Returns:
|
|
2506
|
+
The index of the added shape
|
|
2507
|
+
|
|
2113
2508
|
"""
|
|
2114
2509
|
|
|
2115
|
-
q = rot
|
|
2510
|
+
q = wp.quat(rot)
|
|
2116
2511
|
sqh = math.sqrt(0.5)
|
|
2117
2512
|
if up_axis == 0:
|
|
2118
|
-
q = wp.mul(
|
|
2513
|
+
q = wp.mul(q, wp.quat(0.0, 0.0, -sqh, sqh))
|
|
2119
2514
|
elif up_axis == 2:
|
|
2120
|
-
q = wp.mul(
|
|
2515
|
+
q = wp.mul(q, wp.quat(sqh, 0.0, 0.0, sqh))
|
|
2121
2516
|
|
|
2122
2517
|
return self._add_shape(
|
|
2123
2518
|
body,
|
|
2124
|
-
pos,
|
|
2125
|
-
q,
|
|
2519
|
+
wp.vec3(pos),
|
|
2520
|
+
wp.quat(q),
|
|
2126
2521
|
GEO_CAPSULE,
|
|
2127
|
-
(radius, half_height, 0.0
|
|
2522
|
+
wp.vec3(radius, half_height, 0.0),
|
|
2128
2523
|
None,
|
|
2129
2524
|
density,
|
|
2130
2525
|
ke,
|
|
@@ -2158,7 +2553,7 @@ class ModelBuilder:
|
|
|
2158
2553
|
"""Adds a cylinder collision shape to a body.
|
|
2159
2554
|
|
|
2160
2555
|
Args:
|
|
2161
|
-
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)
|
|
2162
2557
|
pos: The location of the shape with respect to the parent frame
|
|
2163
2558
|
rot: The rotation of the shape with respect to the parent frame
|
|
2164
2559
|
radius: The radius of the cylinder
|
|
@@ -2174,6 +2569,9 @@ class ModelBuilder:
|
|
|
2174
2569
|
thickness: Thickness to use for computing inertia of a hollow cylinder, and for collision handling
|
|
2175
2570
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
2176
2571
|
|
|
2572
|
+
Returns:
|
|
2573
|
+
The index of the added shape
|
|
2574
|
+
|
|
2177
2575
|
"""
|
|
2178
2576
|
|
|
2179
2577
|
q = rot
|
|
@@ -2185,10 +2583,10 @@ class ModelBuilder:
|
|
|
2185
2583
|
|
|
2186
2584
|
return self._add_shape(
|
|
2187
2585
|
body,
|
|
2188
|
-
pos,
|
|
2189
|
-
q,
|
|
2586
|
+
wp.vec3(pos),
|
|
2587
|
+
wp.quat(q),
|
|
2190
2588
|
GEO_CYLINDER,
|
|
2191
|
-
(radius, half_height, 0.0
|
|
2589
|
+
wp.vec3(radius, half_height, 0.0),
|
|
2192
2590
|
None,
|
|
2193
2591
|
density,
|
|
2194
2592
|
ke,
|
|
@@ -2222,7 +2620,7 @@ class ModelBuilder:
|
|
|
2222
2620
|
"""Adds a cone collision shape to a body.
|
|
2223
2621
|
|
|
2224
2622
|
Args:
|
|
2225
|
-
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)
|
|
2226
2624
|
pos: The location of the shape with respect to the parent frame
|
|
2227
2625
|
rot: The rotation of the shape with respect to the parent frame
|
|
2228
2626
|
radius: The radius of the cone
|
|
@@ -2238,6 +2636,9 @@ class ModelBuilder:
|
|
|
2238
2636
|
thickness: Thickness to use for computing inertia of a hollow cone, and for collision handling
|
|
2239
2637
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
2240
2638
|
|
|
2639
|
+
Returns:
|
|
2640
|
+
The index of the added shape
|
|
2641
|
+
|
|
2241
2642
|
"""
|
|
2242
2643
|
|
|
2243
2644
|
q = rot
|
|
@@ -2249,10 +2650,10 @@ class ModelBuilder:
|
|
|
2249
2650
|
|
|
2250
2651
|
return self._add_shape(
|
|
2251
2652
|
body,
|
|
2252
|
-
pos,
|
|
2253
|
-
q,
|
|
2653
|
+
wp.vec3(pos),
|
|
2654
|
+
wp.quat(q),
|
|
2254
2655
|
GEO_CONE,
|
|
2255
|
-
(radius, half_height, 0.0
|
|
2656
|
+
wp.vec3(radius, half_height, 0.0),
|
|
2256
2657
|
None,
|
|
2257
2658
|
density,
|
|
2258
2659
|
ke,
|
|
@@ -2268,10 +2669,10 @@ class ModelBuilder:
|
|
|
2268
2669
|
def add_shape_mesh(
|
|
2269
2670
|
self,
|
|
2270
2671
|
body: int,
|
|
2271
|
-
pos: Vec3 = (0.0, 0.0, 0.0),
|
|
2272
|
-
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),
|
|
2273
2674
|
mesh: Mesh = None,
|
|
2274
|
-
scale: Vec3 = (1.0, 1.0, 1.0),
|
|
2675
|
+
scale: Vec3 = wp.vec3(1.0, 1.0, 1.0),
|
|
2275
2676
|
density: float = default_shape_density,
|
|
2276
2677
|
ke: float = default_shape_ke,
|
|
2277
2678
|
kd: float = default_shape_kd,
|
|
@@ -2285,7 +2686,7 @@ class ModelBuilder:
|
|
|
2285
2686
|
"""Adds a triangle mesh collision shape to a body.
|
|
2286
2687
|
|
|
2287
2688
|
Args:
|
|
2288
|
-
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)
|
|
2289
2690
|
pos: The location of the shape with respect to the parent frame
|
|
2290
2691
|
rot: The rotation of the shape with respect to the parent frame
|
|
2291
2692
|
mesh: The mesh object
|
|
@@ -2300,6 +2701,9 @@ class ModelBuilder:
|
|
|
2300
2701
|
thickness: Thickness to use for computing inertia of a hollow mesh, and for collision handling
|
|
2301
2702
|
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
2302
2703
|
|
|
2704
|
+
Returns:
|
|
2705
|
+
The index of the added shape
|
|
2706
|
+
|
|
2303
2707
|
"""
|
|
2304
2708
|
|
|
2305
2709
|
return self._add_shape(
|
|
@@ -2307,7 +2711,7 @@ class ModelBuilder:
|
|
|
2307
2711
|
pos,
|
|
2308
2712
|
rot,
|
|
2309
2713
|
GEO_MESH,
|
|
2310
|
-
(scale[0], scale[1], scale[2]
|
|
2714
|
+
wp.vec3(scale[0], scale[1], scale[2]),
|
|
2311
2715
|
mesh,
|
|
2312
2716
|
density,
|
|
2313
2717
|
ke,
|
|
@@ -2320,6 +2724,61 @@ class ModelBuilder:
|
|
|
2320
2724
|
has_ground_collision=has_ground_collision,
|
|
2321
2725
|
)
|
|
2322
2726
|
|
|
2727
|
+
def add_shape_sdf(
|
|
2728
|
+
self,
|
|
2729
|
+
body: int,
|
|
2730
|
+
pos: Vec3 = (0.0, 0.0, 0.0),
|
|
2731
|
+
rot: Quat = (0.0, 0.0, 0.0, 1.0),
|
|
2732
|
+
sdf: SDF = None,
|
|
2733
|
+
scale: Vec3 = (1.0, 1.0, 1.0),
|
|
2734
|
+
density: float = default_shape_density,
|
|
2735
|
+
ke: float = default_shape_ke,
|
|
2736
|
+
kd: float = default_shape_kd,
|
|
2737
|
+
kf: float = default_shape_kf,
|
|
2738
|
+
mu: float = default_shape_mu,
|
|
2739
|
+
restitution: float = default_shape_restitution,
|
|
2740
|
+
is_solid: bool = True,
|
|
2741
|
+
thickness: float = default_geo_thickness,
|
|
2742
|
+
):
|
|
2743
|
+
"""Adds SDF collision shape to a body.
|
|
2744
|
+
|
|
2745
|
+
Args:
|
|
2746
|
+
body: The index of the parent body this shape belongs to (use -1 for static shapes)
|
|
2747
|
+
pos: The location of the shape with respect to the parent frame
|
|
2748
|
+
rot: The rotation of the shape with respect to the parent frame
|
|
2749
|
+
sdf: The sdf object
|
|
2750
|
+
scale: Scale to use for the collider
|
|
2751
|
+
density: The density of the shape
|
|
2752
|
+
ke: The contact elastic stiffness
|
|
2753
|
+
kd: The contact damping stiffness
|
|
2754
|
+
kf: The contact friction stiffness
|
|
2755
|
+
mu: The coefficient of friction
|
|
2756
|
+
restitution: The coefficient of restitution
|
|
2757
|
+
is_solid: If True, the mesh is solid, otherwise it is a hollow surface with the given wall thickness
|
|
2758
|
+
thickness: Thickness to use for computing inertia of a hollow mesh, and for collision handling
|
|
2759
|
+
has_ground_collision: If True, the mesh will collide with the ground plane if `Model.ground` is True
|
|
2760
|
+
|
|
2761
|
+
Returns:
|
|
2762
|
+
The index of the added shape
|
|
2763
|
+
|
|
2764
|
+
"""
|
|
2765
|
+
return self._add_shape(
|
|
2766
|
+
body,
|
|
2767
|
+
wp.vec3(pos),
|
|
2768
|
+
wp.quat(rot),
|
|
2769
|
+
GEO_SDF,
|
|
2770
|
+
wp.vec3(scale[0], scale[1], scale[2]),
|
|
2771
|
+
sdf,
|
|
2772
|
+
density,
|
|
2773
|
+
ke,
|
|
2774
|
+
kd,
|
|
2775
|
+
kf,
|
|
2776
|
+
mu,
|
|
2777
|
+
restitution,
|
|
2778
|
+
thickness,
|
|
2779
|
+
is_solid,
|
|
2780
|
+
)
|
|
2781
|
+
|
|
2323
2782
|
def _shape_radius(self, type, scale, src):
|
|
2324
2783
|
"""
|
|
2325
2784
|
Calculates the radius of a sphere that encloses the shape, used for broadphase collision detection.
|
|
@@ -2399,7 +2858,7 @@ class ModelBuilder:
|
|
|
2399
2858
|
|
|
2400
2859
|
(m, c, I) = compute_shape_mass(type, scale, src, density, is_solid, thickness)
|
|
2401
2860
|
|
|
2402
|
-
self._update_body_mass(body, m, I,
|
|
2861
|
+
self._update_body_mass(body, m, I, pos + c, rot)
|
|
2403
2862
|
return shape
|
|
2404
2863
|
|
|
2405
2864
|
# particles
|
|
@@ -2494,9 +2953,9 @@ class ModelBuilder:
|
|
|
2494
2953
|
|
|
2495
2954
|
"""
|
|
2496
2955
|
# compute basis for 2D rest pose
|
|
2497
|
-
p =
|
|
2498
|
-
q =
|
|
2499
|
-
r =
|
|
2956
|
+
p = self.particle_q[i]
|
|
2957
|
+
q = self.particle_q[j]
|
|
2958
|
+
r = self.particle_q[k]
|
|
2500
2959
|
|
|
2501
2960
|
qp = q - p
|
|
2502
2961
|
rp = r - p
|
|
@@ -2634,7 +3093,7 @@ class ModelBuilder:
|
|
|
2634
3093
|
The volume of the tetrahedron
|
|
2635
3094
|
|
|
2636
3095
|
Note:
|
|
2637
|
-
The tetrahedron is created with a rest-pose based on the particle's initial
|
|
3096
|
+
The tetrahedron is created with a rest-pose based on the particle's initial configuration
|
|
2638
3097
|
|
|
2639
3098
|
"""
|
|
2640
3099
|
# compute basis for 2D rest pose
|
|
@@ -2693,13 +3152,13 @@ class ModelBuilder:
|
|
|
2693
3152
|
"""
|
|
2694
3153
|
# compute rest angle
|
|
2695
3154
|
if rest is None:
|
|
2696
|
-
x1 =
|
|
2697
|
-
x2 =
|
|
2698
|
-
x3 =
|
|
2699
|
-
x4 =
|
|
3155
|
+
x1 = self.particle_q[i]
|
|
3156
|
+
x2 = self.particle_q[j]
|
|
3157
|
+
x3 = self.particle_q[k]
|
|
3158
|
+
x4 = self.particle_q[l]
|
|
2700
3159
|
|
|
2701
|
-
n1 = wp.normalize(
|
|
2702
|
-
n2 = wp.normalize(
|
|
3160
|
+
n1 = wp.normalize(wp.cross(x3 - x1, x4 - x1))
|
|
3161
|
+
n2 = wp.normalize(wp.cross(x4 - x2, x3 - x2))
|
|
2703
3162
|
e = wp.normalize(x4 - x3)
|
|
2704
3163
|
|
|
2705
3164
|
d = np.clip(np.dot(n2, n1), -1.0, 1.0)
|
|
@@ -2805,6 +3264,9 @@ class ModelBuilder:
|
|
|
2805
3264
|
tri_lift: float = default_tri_lift,
|
|
2806
3265
|
edge_ke: float = default_edge_ke,
|
|
2807
3266
|
edge_kd: float = default_edge_kd,
|
|
3267
|
+
add_springs: bool = False,
|
|
3268
|
+
spring_ke: float = default_spring_ke,
|
|
3269
|
+
spring_kd: float = default_spring_kd,
|
|
2808
3270
|
):
|
|
2809
3271
|
"""Helper to create a regular planar cloth grid
|
|
2810
3272
|
|
|
@@ -2836,8 +3298,8 @@ class ModelBuilder:
|
|
|
2836
3298
|
|
|
2837
3299
|
for y in range(0, dim_y + 1):
|
|
2838
3300
|
for x in range(0, dim_x + 1):
|
|
2839
|
-
g =
|
|
2840
|
-
p =
|
|
3301
|
+
g = wp.vec3(x * cell_x, y * cell_y, 0.0)
|
|
3302
|
+
p = wp.quat_rotate(rot, g) + pos
|
|
2841
3303
|
m = mass
|
|
2842
3304
|
|
|
2843
3305
|
if x == 0 and fix_left:
|
|
@@ -2884,13 +3346,14 @@ class ModelBuilder:
|
|
|
2884
3346
|
self.add_triangle(*tri1, tri_ke, tri_ka, tri_kd, tri_drag, tri_lift)
|
|
2885
3347
|
self.add_triangle(*tri2, tri_ke, tri_ka, tri_kd, tri_drag, tri_lift)
|
|
2886
3348
|
|
|
2887
|
-
end_vertex = len(self.particle_q)
|
|
2888
3349
|
end_tri = len(self.tri_indices)
|
|
2889
3350
|
|
|
2890
3351
|
# bending constraints, could create these explicitly for a grid but this
|
|
2891
3352
|
# is a good test of the adjacency structure
|
|
2892
3353
|
adj = wp.utils.MeshAdjacency(self.tri_indices[start_tri:end_tri], end_tri - start_tri)
|
|
2893
3354
|
|
|
3355
|
+
spring_indices = set()
|
|
3356
|
+
|
|
2894
3357
|
for k, e in adj.edges.items():
|
|
2895
3358
|
# skip open edges
|
|
2896
3359
|
if e.f0 == -1 or e.f1 == -1:
|
|
@@ -2900,6 +3363,19 @@ class ModelBuilder:
|
|
|
2900
3363
|
e.o0, e.o1, e.v0, e.v1, edge_ke=edge_ke, edge_kd=edge_kd
|
|
2901
3364
|
) # opposite 0, opposite 1, vertex 0, vertex 1
|
|
2902
3365
|
|
|
3366
|
+
spring_indices.add((min(e.o0, e.o1), max(e.o0, e.o1)))
|
|
3367
|
+
spring_indices.add((min(e.o0, e.v0), max(e.o0, e.v0)))
|
|
3368
|
+
spring_indices.add((min(e.o0, e.v1), max(e.o0, e.v1)))
|
|
3369
|
+
|
|
3370
|
+
spring_indices.add((min(e.o1, e.v0), max(e.o1, e.v0)))
|
|
3371
|
+
spring_indices.add((min(e.o1, e.v1), max(e.o1, e.v1)))
|
|
3372
|
+
|
|
3373
|
+
spring_indices.add((min(e.v0, e.v1), max(e.v0, e.v1)))
|
|
3374
|
+
|
|
3375
|
+
if add_springs:
|
|
3376
|
+
for i, j in spring_indices:
|
|
3377
|
+
self.add_spring(i, j, spring_ke, spring_kd, control=0.0)
|
|
3378
|
+
|
|
2903
3379
|
def add_cloth_mesh(
|
|
2904
3380
|
self,
|
|
2905
3381
|
pos: Vec3,
|
|
@@ -2918,6 +3394,9 @@ class ModelBuilder:
|
|
|
2918
3394
|
tri_lift: float = default_tri_lift,
|
|
2919
3395
|
edge_ke: float = default_edge_ke,
|
|
2920
3396
|
edge_kd: float = default_edge_kd,
|
|
3397
|
+
add_springs: bool = False,
|
|
3398
|
+
spring_ke: float = default_spring_ke,
|
|
3399
|
+
spring_kd: float = default_spring_kd,
|
|
2921
3400
|
):
|
|
2922
3401
|
"""Helper to create a cloth model from a regular triangle mesh
|
|
2923
3402
|
|
|
@@ -2945,7 +3424,7 @@ class ModelBuilder:
|
|
|
2945
3424
|
|
|
2946
3425
|
# particles
|
|
2947
3426
|
for v in vertices:
|
|
2948
|
-
p =
|
|
3427
|
+
p = wp.quat_rotate(rot, v * scale) + pos
|
|
2949
3428
|
|
|
2950
3429
|
self.add_particle(p, vel, 0.0)
|
|
2951
3430
|
|
|
@@ -2974,7 +3453,10 @@ class ModelBuilder:
|
|
|
2974
3453
|
|
|
2975
3454
|
adj = wp.utils.MeshAdjacency(self.tri_indices[start_tri:end_tri], end_tri - start_tri)
|
|
2976
3455
|
|
|
2977
|
-
edgeinds = np.
|
|
3456
|
+
edgeinds = np.fromiter(
|
|
3457
|
+
(x for e in adj.edges.values() if e.f0 != -1 and e.f1 != -1 for x in (e.o0, e.o1, e.v0, e.v1)),
|
|
3458
|
+
int,
|
|
3459
|
+
).reshape(-1, 4)
|
|
2978
3460
|
self.add_edges(
|
|
2979
3461
|
edgeinds[:, 0],
|
|
2980
3462
|
edgeinds[:, 1],
|
|
@@ -2984,6 +3466,21 @@ class ModelBuilder:
|
|
|
2984
3466
|
edge_kd=[edge_kd] * len(edgeinds),
|
|
2985
3467
|
)
|
|
2986
3468
|
|
|
3469
|
+
if add_springs:
|
|
3470
|
+
spring_indices = set()
|
|
3471
|
+
for i, j, k, l in edgeinds:
|
|
3472
|
+
spring_indices.add((min(i, j), max(i, j)))
|
|
3473
|
+
spring_indices.add((min(i, k), max(i, k)))
|
|
3474
|
+
spring_indices.add((min(i, l), max(i, l)))
|
|
3475
|
+
|
|
3476
|
+
spring_indices.add((min(j, k), max(j, k)))
|
|
3477
|
+
spring_indices.add((min(j, l), max(j, l)))
|
|
3478
|
+
|
|
3479
|
+
spring_indices.add((min(k, l), max(k, l)))
|
|
3480
|
+
|
|
3481
|
+
for i, j in spring_indices:
|
|
3482
|
+
self.add_spring(i, j, spring_ke, spring_kd, control=0.0)
|
|
3483
|
+
|
|
2987
3484
|
def add_particle_grid(
|
|
2988
3485
|
self,
|
|
2989
3486
|
pos: Vec3,
|
|
@@ -3000,13 +3497,14 @@ class ModelBuilder:
|
|
|
3000
3497
|
radius_mean: float = default_particle_radius,
|
|
3001
3498
|
radius_std: float = 0.0,
|
|
3002
3499
|
):
|
|
3500
|
+
rng = np.random.default_rng()
|
|
3003
3501
|
for z in range(dim_z):
|
|
3004
3502
|
for y in range(dim_y):
|
|
3005
3503
|
for x in range(dim_x):
|
|
3006
|
-
v =
|
|
3504
|
+
v = wp.vec3(x * cell_x, y * cell_y, z * cell_z)
|
|
3007
3505
|
m = mass
|
|
3008
3506
|
|
|
3009
|
-
p =
|
|
3507
|
+
p = wp.quat_rotate(rot, v) + pos + wp.vec3(rng.random(3) * jitter)
|
|
3010
3508
|
|
|
3011
3509
|
if radius_std > 0.0:
|
|
3012
3510
|
r = radius_mean + np.random.randn() * radius_std
|
|
@@ -3072,7 +3570,7 @@ class ModelBuilder:
|
|
|
3072
3570
|
for z in range(dim_z + 1):
|
|
3073
3571
|
for y in range(dim_y + 1):
|
|
3074
3572
|
for x in range(dim_x + 1):
|
|
3075
|
-
v =
|
|
3573
|
+
v = wp.vec3(x * cell_x, y * cell_y, z * cell_z)
|
|
3076
3574
|
m = mass
|
|
3077
3575
|
|
|
3078
3576
|
if fix_left and x == 0:
|
|
@@ -3087,7 +3585,7 @@ class ModelBuilder:
|
|
|
3087
3585
|
if fix_bottom and y == 0:
|
|
3088
3586
|
m = 0.0
|
|
3089
3587
|
|
|
3090
|
-
p =
|
|
3588
|
+
p = wp.quat_rotate(rot, v) + pos
|
|
3091
3589
|
|
|
3092
3590
|
self.add_particle(p, vel, m)
|
|
3093
3591
|
|
|
@@ -3177,7 +3675,6 @@ class ModelBuilder:
|
|
|
3177
3675
|
num_tets = int(len(indices) / 4)
|
|
3178
3676
|
|
|
3179
3677
|
start_vertex = len(self.particle_q)
|
|
3180
|
-
start_tri = len(self.tri_indices)
|
|
3181
3678
|
|
|
3182
3679
|
# dict of open faces
|
|
3183
3680
|
faces = {}
|
|
@@ -3255,8 +3752,8 @@ class ModelBuilder:
|
|
|
3255
3752
|
else:
|
|
3256
3753
|
self.body_inv_mass[i] = 0.0
|
|
3257
3754
|
|
|
3258
|
-
if
|
|
3259
|
-
self.body_inv_inertia[i] =
|
|
3755
|
+
if any(x for x in new_inertia):
|
|
3756
|
+
self.body_inv_inertia[i] = wp.inverse(new_inertia)
|
|
3260
3757
|
else:
|
|
3261
3758
|
self.body_inv_inertia[i] = new_inertia
|
|
3262
3759
|
|
|
@@ -3338,6 +3835,7 @@ class ModelBuilder:
|
|
|
3338
3835
|
m._particle_radius = wp.array(self.particle_radius, dtype=wp.float32, requires_grad=requires_grad)
|
|
3339
3836
|
m.particle_flags = wp.array([flag_to_int(f) for f in self.particle_flags], dtype=wp.uint32)
|
|
3340
3837
|
m.particle_max_radius = np.max(self.particle_radius) if len(self.particle_radius) > 0 else 0.0
|
|
3838
|
+
m.particle_max_velocity = self.particle_max_velocity
|
|
3341
3839
|
|
|
3342
3840
|
# hash-grid for particle interactions
|
|
3343
3841
|
m.particle_grid = wp.HashGrid(128, 128, 128)
|
|
@@ -3393,6 +3891,9 @@ class ModelBuilder:
|
|
|
3393
3891
|
m.spring_stiffness = wp.array(self.spring_stiffness, dtype=wp.float32, requires_grad=requires_grad)
|
|
3394
3892
|
m.spring_damping = wp.array(self.spring_damping, dtype=wp.float32, requires_grad=requires_grad)
|
|
3395
3893
|
m.spring_control = wp.array(self.spring_control, dtype=wp.float32, requires_grad=requires_grad)
|
|
3894
|
+
m.spring_constraint_lambdas = wp.array(
|
|
3895
|
+
shape=len(self.spring_rest_length), dtype=wp.float32, requires_grad=requires_grad
|
|
3896
|
+
)
|
|
3396
3897
|
|
|
3397
3898
|
# ---------------------
|
|
3398
3899
|
# triangles
|
|
@@ -3410,6 +3911,9 @@ class ModelBuilder:
|
|
|
3410
3911
|
m.edge_bending_properties = wp.array(
|
|
3411
3912
|
self.edge_bending_properties, dtype=wp.float32, requires_grad=requires_grad
|
|
3412
3913
|
)
|
|
3914
|
+
m.edge_constraint_lambdas = wp.array(
|
|
3915
|
+
shape=len(self.edge_rest_angle), dtype=wp.float32, requires_grad=requires_grad
|
|
3916
|
+
)
|
|
3413
3917
|
|
|
3414
3918
|
# ---------------------
|
|
3415
3919
|
# tetrahedra
|